Golang超详细入门教程

Golang超详细入门教程

一、数据类型转换

  1. C语言中数据可以隐式转换或显示转换, 但是Go语言中数据只能显示转换
  2. 格式: 数据类型(需要转换的数据)
  3. 注意点: 和C语言一样数据可以从大类型转换为小类型, 也可以从小类型转换为大类型. 但是大类型转换为小类型可能会丢失精度

Go语言中不能通过 数据类型(变量)的格式将数值类型转换为字符串, 也不能通过 数据类型(变量)的格式将字符串转换为数值类型

package main
import "fmt"
func main() {
   
    var num1 int32 = 65
    // 可以将整型强制转换, 但是会按照ASCII码表来转换
    // 但是不推荐这样使用
    var str1 string = string(num1)
    fmt.Println(str1)
    
    var num2 float32 = 3.14
    // 不能将其它基本类型强制转换为字符串类型
    var str2 string = string(num2)
    fmt.Println(str2)
    
    var str3 string = "97"
    // 不能强制转换, cannot convert str2 (type string) to type int
    var num3 int = int(str3)
    fmt.Println(num3)
}

其它类型转字符串类型 strconv.FormatXxx()

package main
import (
    "fmt"
    "strconv"
)
func main() {
   
    // 字符串转换成字符切片
    slice := []byte("hello") // 强制类型转换  string-->[]byte
    fmt.Println(slice)       // [104 101 108 108 111]
    // 字符切片转换成字符串
    slice2 := []byte{
   'h', 'e', 'l', 'l', 'o', 97}
    fmt.Println(string(slice2)) // helloa  强制类型转换  []byte-->string

    // strconv.FormatXXX() 其他类型转换成字符串
    str1 := strconv.FormatBool(true)                   // bool-->string
    fmt.Println(str1)                                  // true
    fmt.Println(strconv.FormatInt(123, 10))            // 123  int-->string  10表示十进制
    fmt.Println(strconv.Itoa(123))                     // 123  十进制int-->string
    fmt.Println(strconv.FormatFloat(3.14, 'f', 6, 64)) // 3.140000  float-->string  6:保留6位  64:float64
}

字符串类型转其它类型 strconv.ParseXxx()

package main
import (
    "fmt"
    "strconv"
)
func main() {
   
    // strconv.ParseXXX()  字符串转换成其他类型
    // strconv.ParseBool()  string-->bool
    b, err_info := strconv.ParseBool("false")
    if err_info != nil {
    // 如果有错误信息
        fmt.Println("类型转换出错")
    } else {
   
        fmt.Println(b) // false
    }

    // strconv.ParseInt()   string-->int64
    val, err_info := strconv.ParseInt("11011001", 2, 64) // 2:二进制  64:int64
    fmt.Println(val)                                     // 217

    // strconv.ParseFloat()   string-->float64
    val2, err_info := strconv.ParseFloat("3.1415", 64) // 64:float64
    fmt.Println(val2)                                  // 3.1415

    // strconv.Atoi()  string-->十进制int
    val3, _ := strconv.Atoi("123")
    fmt.Println(val3) // 123
}

二、常量

  • 在常量组中, 如果上一行常量有初始值,但是下一行没有初始值, 那么下一行的值就是上一行的值
  • 定义的局部变量或者导入的包没有被使用, 那么编译器会报错,无法编译运行
  • 但是定义的常量没有被使用,编译器不会报错, 可以编译运行

image.png

package main
import "fmt"
func main() {
   
    const (
        a = iota //0
        b        //1
        c        //2
        d = "ha" //独立值,iota += 1
        e        //"ha"   iota += 1
        f = 100  //iota +=1
        g        //100  iota +=1
        h = iota //7,恢复计数
        i        //8
    )
    fmt.Println(a, b, c, d, e, f, g, h, i)
}
0 1 2 ha ha 100 100 7 8

三、输入输出函数

1.输出函数

func Printf(format string, a …interface{}) (n int, err error)

  1. Go语言Printf函数其它特性,如宽度、标志、精度、长度、转移符号等,和C语言一样.
  2. Go语言中输出某一个值,很少使用%d%f等, 一般都使用%v即可
  3. 输出复合类型时会自动生成对应格式后再输出
  4. 除此之外**,Go语言还增加了%v控制符,用于打印所有类型数据**
  5. 除此之外**,Go语言还增加了%T控制符, 用于输出值的类型**
  6. 值得注意的是,输出十进制只能通过%d,不能像C语言一样通过%i
  7. 除了和C语言一样,可以通过%o、%x输出八进制和十六进制外,还可以直接通过%b输出二进制
  8. 和C语言用法几乎一模一样, 只不过新增了一些格式化符号

func Println(a …interface{}) (n int, err error)

  1. 输出之后会在结尾处添加换行
  2. 传入多个参数时, 会自动在相邻参数之间添加空格
  3. 传入符合类型数据时, 会自动生成对应格式后再输出
  4. 采用默认格式将其参数格式化并写入标准输出

func Print(a …interface{}) (n int, err error)

  1. 输出之后不会在结尾处添加换行
  2. 传入多个参数时, 只有两个相邻的参数都不是字符串,才会在相邻参数之间添加空格
  3. 传入符合类型数据时, 会自动生成对应格式后再输出
  4. 和Println几乎一样

以下三个函数和Printf/Println/Print函数一样, 只不过上面三个函数是输出到标准输出, 而下面三个函数可以通过w指定输出到什么地方
func Fprintf(w io.Writer, format string, a …interface{}) (n int, err error)
func Fprintln(w io.Writer, a …interface{}) (n int, err error)
func Fprint(w io.Writer, a …interface{}) (n int, err error)

package main
import (
    "fmt"
    "net/http"
    "os"
)
func main() {
   
    // os.Stdout 写入到标准输出
    name := "lnj"
    age := 33
    // 第一个参数: 指定输出到什么地方
    // 第二个参数: 指定格式控制字符串
    // 第三个参数: 指定要输出的数据
    fmt.Fprintf(os.Stdout, "name = %s, age = %d\n", name, age)

    // http.ResponseWriter 写入到网络响应
    http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
   
        fmt.Fprintf(writer, "name = %s, age = %d\n", name, age)
    })
    http.ListenAndServe(":8888", nil)
}

以下三个函数和Printf/Println/Print函数一样, 只不过上面三个函数是输出到标准输出, 而下面三个函数不会输出,而是将字符串返回给我们
func Sprintf(format string, a …interface{}) string
func Sprint(a …interface{}) string
func Sprintln(a …interface{}) string

package main
import (
    "fmt"
)
func main() {
   
    name := "lnj"
    age := 33
    // 按照指定的格式生成字符串
    str := fmt.Sprintf("name = %s, age = %d\n", name, age)
    // 输出生成的字符串
    fmt.Println(str)
}

2.输入函数

func Scanf(format string, a …interface{}) (n int, err error)
func Scan(a …interface{}) (n int, err error)
func Scanln(a …interface{}) (n int, err error)
以下三个函数和Scan/Scanln/Scanf函数一样, 只不过上面三个函数是从标准输入读取数据, 而下面三个函数可以通过r指定从哪读取数据
func Fscanf(r io.Reader, format string, a …interface{}) (n int, err error)
func Fscanln(r io.Reader, a …interface{}) (n int, err error)
func Fscan(r io.Reader, a …interface{}) (n int, err error)

package main
import (
    "fmt"
    "os"
    "strings"
)
func main() {
   
    var num1 int
    var num2 int
    // 第一个参数: 指定从哪读取数据
    // 第二个参数: 指定格式控制字符串
    // 第三个参数: 指定要输出的数据
    fmt.Fscanf(os.Stdin, "%d%d", &num1, &num2)
    fmt.Println(num1, num2)
    s := strings.NewReader("lnj 33")
    var name string
    var age int
    // 从指定字符串中扫描出想要的数据
    // 注意:
    fmt.Fscanf(s, "%s%d", &name, &age)
    fmt.Println("name =", name, "age =", age)
}

以下三个函数和Scan/Scanln/Scanf函数一样, 只不过上面三个函数是从标准输入读取数据, 而下面三个函数是从字符串中读取数据
func Sscan(str string, a …interface{}) (n int, err error)
func Sscanf(str string, format string, a …interface{}) (n int, err error)
func Sscanln(str string, a …interface{}) (n int, err error)

package main
import "fmt"
func main() {
   
    str := "lnj 33"
    var name string
    var age int
    //fmt.Sscanf(str, "%s %d",&name, &age)
    //fmt.Sscanln(str,&name, &age)
    fmt.Sscan(str, &name, &age)
    fmt.Println("name =", name, "age =", age)
}

四、命令行参数

1.go命令行操作指令

go version 查看当前安装的go版本
go env 查看当前go的环境变量
go fmt 格式化代码,会将指定文件中凌乱的代码按照go语言规范格式化
go run 命令文件 编译并运行go程序
go build 编译检查

  1. 对于非命令文件只会执行编译检查, 不会产生任何文件
  2. 对于命令文件除了编译检查外,还会在当前目录下生成一个可执行文件
  3. 对应只想编译某个文件, 可以在命令后面指定文件名称go build 文件名称

go install 安装程序

2.通过os包获取命令行参数

简单介绍:Go语言的 os 包中提供了操作系统函数的接口,是一个比较重要的包。 顾名思义,os 包的作用主要是在服务器上进行系统的基本操作,如文件操作、目录操作、执行命令、信号与中断、进程、系统状态等等。

  1. Go语言中main函数没有形参, 所以不能直接通过main函数获取命令行参数
  2. 想要获取命令行参数必须导入os包, 通过os包的Args获取
  3. 注意点: 无论外界传入的是什么类型, 我们拿到的都是字符串类型

image.png

3.通过flag包获取命令行参数

第一种:
image.png
第二种:
image.png

4.os包和flag包的对比

通过os包获取命令行参数

  1. 如果用户没有传递参数会报错
  2. 需要严格按照代码中的顺序传递参数, 否则会造成数据混乱
  3. 不能指定参数的名称
  4. 获取到的数据都是字符串类型

通过flag包获取命令行参数

  1. 如果用户没有传递参数不会报错
  2. 不需要严格按照代码中的顺序传递参数, 不会造成数据混乱
  3. 可以指定参数的名称
  4. 获取到的数据是我们自己指定的类型

五、流程控制

1.选择语句(if…)

  1. 条件表达式的值必须是布尔类型(**Go语言中没有非零即真的概念**)
  2. 条件表达式前面可以添加初始化语句
  3. 不需要编写圆括号
  4. 左大括号必须和条件语句在同一行
  • 值得一提的是Go语言中没有C语言中的三目运算符, 所以C语言中三目能干的在Go语言中都只能通过if else的形式来完成

2.选择结构(switch…case)

  1. 和if一样,表达式前面**可以添加初始化语句**
  2. 和if一样,不需要编写圆括号
  3. 和if一样,左大括号必须和表达式在同一行
  4. case表达式的值不一定要是常量, 甚至可以不用传递
  5. 一个case后面**可以有多个表达式**, 满足其中一个就算匹配
  6. case后面不需要添加break
  7. 可以在case语句块最后添加fallthrough,实现case穿透
  8. case后面定义变量不需要添加{}明确范围
package main
import "fmt"
func main() {
   
    //第一种
    switch num := 3; num {
   
    case 1, 2, 3, 4, 5:
        fmt.Println("工作日")
    case 6, 7:
        fmt.Println("非工作日")
    default:
        fmt.Println("Other...")
    }
    //第二种
    //case后面不用编写break, 不会出现case穿透问题
    //如果想让case穿透,必须在case语句块最后添加fallthrough关键
    switch num := 1; num {
   
    case 1:
        fallthrough
    case 2:
        fallthrough
    case 3:
        fallthrough
    case 4:
        fallthrough
    case 5:
        fmt.Println("工作日")
        fallthrough
    case 6:
        fmt.Println("结束")
    case 7:
        fmt.Println("非工作日")
    default:
        fmt.Println("Other...")
    }
}

3.循环结构(for )

除了实现基本的循环结构以外,Go语言还实现了一种高级for循环for…range循环,for…range循环可以快速完成对字符串数组slicemapchannel遍历。
格式:for 索引, 值 := range 被遍历数据{ content }

package main
import "fmt"
func main() {
   
    // 1.定义一个数组
    arr := [3]int{
   1, 3, 5}
    // 2.快速遍历数组
    // i用于保存当前遍历到数组的索引
    // v用于保存当前遍历到数组的值
    for i, v := range arr {
   
        fmt.Println(i, v)
    }
}
0 1
1 3
2 5

4.四大跳转

return、break、continue、goto

六、函数

1.值传递和引用传递

  1. Go语言中值类型有: int系列、float系列、bool、string、数组、结构体
    1. 值类型通常在栈中分配存储空间
    2. 值类型作为函数参数传递, 是拷贝传递
    3. 在函数体内修改值类型参数, 不会影响到函数外的值
  2. Go语言中引用类型有: 指针、slice、map、channel
    1. 引用类型通常在堆中分配存储空间
    2. 引用类型作为函数参数传递,是引用传递
    3. 在函数体内修改引用类型参数,会影响到函数外的值
      1. slice是一个24Byte的结构体。
      2. map和channel都是8Byte的指针。
      3. slice、map、channel使用的是浅拷贝,形参实参会通过指针共享数据,所以会相互影响。但是golang对这三个结构体做了封装,从广义上来定义引用的话(通过别名去修改原数据),那这三个数据类型也属于引用类型。

2.匿名函数

匿名函数也是函数的一种, 它的格式和普通函数一模一样,只不过没有名字而已。
匿名函数可以定义在函数外(全局匿名函数),也可以定义在函数内(局部匿名函数), Go语言中的普通函数不能嵌套定义, 但是可以通过匿名函数来实现函数的嵌套定义。

  • 全局匿名函数

一般情况下我们很少使用全局匿名函数, 大多数情况都是使用局部匿名函数, 匿名函数可以直接调用、保存到变量、作为参数或者返回值。

  • 匿名函数应用场景
    • 当某个函数只需要被调用一次时, 可以使用匿名函数
    • 需要执行一些不确定的操作时,可以使用匿名函数

3.闭包(特殊的匿名函数)

  • 只要闭包还在使用外界的变量, 那么外界的变量就会一直存在
  • 闭包中使用的变量和外界的变量是同一个变量, 所以可以闭包中可以修改外界变量
  • 也就是说只要匿名函数中用到了外界的变量, 那么这个匿名函数就是一个闭包

4.延迟调用

  • Go语言中没有提供其它面向对象语言的析构函数, 但是Go语言提供了defer语句用于实现其它面向对象语言析构函数的功能。
  • defer语句常用于释放资源、解除锁定以及错误处理等。
  • 无论你在什么地方注册defer语句,它都会在所属函数执行完毕之后才会执行, 并且如果注册了多个defer语句,那么它们会按照后进先出的原则执行。

使用建议:  
一个函数中,有多个条件分支使用 return 结束函数运行的情况下,同时有资源打开需要关闭的情况下,建议使用 defer,在资源打开后直接使用 defer 注册关闭该资源的代码,这样可以避免忘记关闭资源操作。例如打开一个文件,然后读取内容,内容转换处理,然后关闭文件。这个流程就可以改成 打开文件、延迟关闭文件、读取内容、内容转换处理
defer 不要在循环中使用,也不要对命名返回值变量操作,否则会出现很难理解的意外结果。defer 使用的位置如果不正确,会有可能导致宕机(panic),所以有错误检查的语句的,最好放在错误检查语句之后。

5.init 函数

  • golang里面有两个保留的函数:
    • init函数(能够应用于所有的package)

注:init函数用于处理当前文件的初始化操作, 在使用某个文件时的一些准备工作应该放到这里。

  • main函数(只能应用于package main)
  • 这两个函数在定义时不能有任何的参数和返回值。
  • go程序会自动调用init()和main(),所以你不能在任何地方调用这两个函数。
  • package main必须包含一个main函数, 但是每个package中的init函数都是可选的。
  • 一个package里面可以写任意多个init函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个package中每个文件只写一个init函数。

image.png

package main
import "fmt"
const constValue = 998        // 1
var gloalVarValue int = abc() // 2
func init() {
    // 3
    fmt.Println("执行main包中main.go中init函数")
}
func main() {
    // 4
    fmt.Println("执行main包中main.go中main函数")
}
func abc() int {
   
    fmt.Println("执行main包中全局变量初始化")
    return 998
}
执行main包中全局变量初始化
执行main包中main.go中init函数
执行main包中main.go中main函数

七、数组和切片

1.数组

	var a1 [3]int = [3]int{
   1, 3, 5}
	var a2 [3]int = [3]int{
   8}
	var a3 = [3]int{
   0: 8, 2: 9}
	var a4 [3]int
	fmt.Println(a1, a2, a3, a4)
[1 3 5] [8 0 0] [8 0 9] [0 0 0]
    arr := [...]int{
   1, 3, 5}
    // 传统for循环遍历
    for i := 0; i < len(arr); i++ {
   
        fmt.Println(i, arr[i])
    }
0 1
1 3
2 5
    // for...range循环遍历
    for i, v := range arr {
   
        fmt.Println(i, v)
    }
0 1
1 3
2 5

2.切片

  • 在实际开发中我们可能事先不能确定数组的长度, 为了解决这类问题Go语言中推出了一种新的数据类型切片。
  • 切片可以简单的理解为长度可以变化的数组, 但是Go语言中的切片本质上是一个结构体。
  • image.png

切片的使用

	sce := make([]int, 3, 5)
	sce = append(sce, 1, 2, 3, 4, 5, 6)
	fmt.Println(sce)
	//首部添加元素,  ... 可变参数
	sce = append([]int{
   110, 120}, sce...)
	fmt.Println(sce)
	//中间添加元素
	sce = append(sce[:2], append([]int{
   123, 456
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大华Coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值