Go 语言基础学习文档

51 阅读10分钟

Go 语言基础学习文档

一、环境搭建

1.1 下载与安装

1.2 安装验证

  1. 验证有没有安装成功

    go version
    

    打印输出类似”go version go1.24.2 windows/amd64“,说明安装成功。

  2. 查看 Go 环境

    go env
    

    Go1.11 版本之后无需手动配置环境变量,使用 go mod 管理项目,也不需要非得把项目放到 GOPATH 目录下,你可以在任意位置新建项目。

    Go1.13 以后可以彻底不要 GOPATH 了。

1.3 开发工具

  1. 推荐使用 VSCode
  2. VSCode 安装 Go 语言插件(插件名称:Go)

二、基础语法

2.1 fmt 模块(格式化输出)

2.1.1 Print

用于基本打印输出,多参数打印无空格。

fmt.Print("a")
// a

fmt.Print("a", "b", "c")
// abc (PS:打印多个时,不会有空格)
2.1.2 Println

用于打印输出并支持格式化。

fmt.Println("a")
// a
// 换行

fmt.Println("a", "b", "c")
// a b c (PS:打印多个时,会有空格)
// 换行
2.1.3 Printf

用于格式化打印输出,支持占位符。

var a = 1
var b = 2
var c = 3

fmt.Printf("a=%v,b=%v,c=%v", a, b, c)
// a=1,b=2,c=3

fmt.Printf("a=%v,a的类型是%T", a, a)
// a=1,a的类型是int

2.2 变量与常量

2.2.1 变量

变量是程序运行过程中可以改变的量,Go 语言支持两种声明方式。

  1. var 变量声明法

    • 适用范围:可用于全局变量和局部变量。

    • 基本用法

      // 声明变量
      var a string
      // 变量赋值
      a = "a"
      
      // 声明变量并赋值
      var a string = "a"
      // 声明变量并赋值,简写(类型推导,可省略)
      vat a = "a"
      
      // 一次声明多个变量(多个变量的类型都一样)
      var a, b, c, string
      a = "a"
      b = "b"
      c = "c"
      
      // 一次声明多个变量,(多个变量的类型可以不一样)
      var (
      	a string
      	b int
      	c bool
      )
      
      // 一次声明多个变量并赋值
      var (
      	a string = "a"
      	b int    = 1
      	c bool   = true
      )
      
      // 一次声明多个变量并赋值,简写(类型推导,可省略)
      var (
      	a = "a"
      	b = 1
      	c = true
      )
      
  2. 短变量声明法

    • 适用范围:仅用于函数内部的局部变量。

    • 基本用法

      // 声明变量并赋值
      a := "a"
      
      // 一次声明多个变量并赋值
      a, b, c := "a", 1, true
      
2.2.2 常量

常量是恒定不变的值,定义时必须赋值。

  1. const 定义常量

    // 声明常量并赋值
    const a = "a"
    
    // 一次性声明多个常量并赋值
    const (
    	a = "a"
        b = "b"
    )
    
  2. 常量省略值的特性

    同时声明多个常量时,若省略值,则表示和上一行的值相同。

    const (
    	a = "a"
    	b
    	c
    )
    fmt.Printf("a = %v, b = %v, c = %v\n", a, b, c)
    // a = a, b = a, c = a
    

2.3 数据类型

Go 语言数据类型分为 基本数据类型复合数据类型 两大类。

  • 基本数据类型:整型、浮点型、布尔型、字符串
  • 复合数据类型:数组、切片、结构体、函数、map、通道(channel)、接口等
2.3.1 整型 int

整型分为 有符号整型无符号整型 两类,不同类型占用字节数不同。

  1. 声明示例

    var num int = 1
    fmt.Printf("num=%v,类型=%T\n", num, num)
    // num=1,类型=int
    
  2. 整型分类

    类型有无符号位数取值范围备注
    int8有符号8-128 到 127(-2^7到2^7-1)
    int16有符号16-32768 到 32767(-2^15到2^15-1)
    int32有符号32-2147483648 到 2147483647(-2^31到2^31-1)别名:rune
    int64有符号64-9223372036854775808 到 9223372036854775807(-2^63到2^63-1)
    uint8无符号80 到 255(0到2^8-1)别名:byte
    uint16无符号160 到 65535(0到2^16-1)
    uint32无符号320 到 4294967295(0到2^32-1)
    uint64无符号640 到 18446744073709551615(0到2^64-1)
    int有符号系统相关32位系统同int32,64位系统同int64推荐优先使用
    uint无符号系统相关32位系统同uint32,64位系统同uint64
    uintptr无符号系统相关足够存储指针值的无符号整数用于底层编程(如指针操作)
  3. 整型类型转换

    不同整型之间无法直接运算,需要强制类型转换,高位转低位时需注意数据溢出。

    // 不同类型直接运算报错
    var num1 int8 = 1
    var num2 int16 = 1
    fmt.Println(num1 + num2) // 报错
    
    // 强制类型转换后运算
    var num1 int8 = 1
    var num2 int16 = 1
    fmt.Println(int16(num1) + num2) // 输出:2
    
    // 高位转低位的溢出问题
    var num1 int16 = 130
    fmt.Println(int8(num1)) // 输出:-126
    
  4. 数字字面量格式

    符号描述
    %d表示十进制输出
    %b表示二进制输出
    %o表示八进制输出
    %x表示十六进制输出

    示例代码

    num := 16
    fmt.Printf("num=%v\n", num)  // 输出:num=16
    fmt.Printf("num=%d\n", num)  // 输出:num=16
    fmt.Printf("num=%b\n", num)  // 输出:num=10000
    fmt.Printf("num=%o\n", num)  // 输出:num=20
    fmt.Printf("num=%x\n", num)  // 输出:num=10
    
  5. 获取变量占用字节数

    使用 unsafe.Sizeof 函数可以返回变量占用的字节数。

    num1 := int(1)
    num2 := int8(1)
    num3 := int16(1)
    num4 := int32(1)
    num5 := int64(1)
    
    fmt.Println(unsafe.Sizeof(num1)) // 输出:8
    fmt.Println(unsafe.Sizeof(num2)) // 输出:1
    fmt.Println(unsafe.Sizeof(num3)) // 输出:2
    fmt.Println(unsafe.Sizeof(num4)) // 输出:4
    fmt.Println(unsafe.Sizeof(num5)) // 输出:8
    
2.3.2 浮点型 float

Go 语言支持两种浮点型:float32float64

  1. 声明示例

    // 类型推导,默认是float64
    num := 3.1415926
    fmt.Printf("num=%v,类型=%T\n", num, num) // 输出:num=3.1415926,类型=float64
    
    // 显式声明float32
    num1 := float32(3.1415926)
    fmt.Printf("num1=%v,类型=%T\n", num1, num1) // 输出:num1=3.1415925,类型=float32
    
    // 显式声明float64
    num2 := float64(3.1415926)
    fmt.Printf("num2=%v,类型=%T\n", num2, num2) // 输出:num2=3.1415926,类型=float64
    
  2. 浮点型范围

    • float32:最大范围约为 3.4e38

    • float64:最大范围约为 1.8e308

      示例代码

      fmt.Println(math.MaxFloat32) // 输出:3.4028234663852886e+38
      fmt.Println(math.MaxFloat64) // 输出:1.7976931348623157e+308
      
  3. 格式化输出

    使用 %f 占位符输出浮点型,可指定小数位数。

    num1 := 3.1415926
    fmt.Printf("%v\n", num1)    // 输出:3.1415926
    fmt.Printf("%f\n", num1)    // 输出:3.141593(默认保留6位,四舍五入)
    fmt.Printf("%.2f\n", num1)  // 输出:3.14(保留2位)
    fmt.Printf("%.3f\n", num1)  // 输出:3.142(保留3位)
    
  4. 科学计数法

    浮点型支持科学计数法表示。

    num1 := 3.14e2
    fmt.Printf("num1=%v,类型=%T\n", num1, num1) // 输出:num1=314,类型=float64
    
    num2 := 3.14e-2
    fmt.Printf("num2=%v,类型=%T\n", num2, num2) // 输出:num2=0.0314,类型=float64
    
  5. 精度丢失问题

    二进制浮点数转换为十进制时可能存在精度丢失,可使用第三方包 github.com/shopspring/decimal 解决。

    num := 1129.6
    fmt.Println(num * 100) // 输出:112959.99999999999
    
    num1 := 8.2
    num2 := 3.8
    fmt.Println(num1 - num2) // 输出:4.3999999999999995
    
  6. 浮点型与整型转换

    • 整型转浮点型:直接强制转换,不会丢失数据

      num1 := 3
      num2 := float32(num1)
      fmt.Printf("num2=%v,类型=%T\n", num2, num2) // 输出:num2=3,类型=float32
      
      num3 := float64(num1)
      fmt.Printf("num3=%v,类型=%T\n", num3, num3) // 输出:num3=3,类型=float64
      
    • 浮点型转整型:强制转换会丢失小数部分

      num1 := 3.14
      num2 := int(num1)
      fmt.Printf("num2=%v,类型=%T\n", num2, num2) // 输出:num2=3,类型=int
      
2.3.2 布尔类型 bool

布尔型用 bool 表示,只有 truefalse 两个值。

  1. 注意事项

    • 布尔型变量默认值为 false
    • 不允许将整型强制转换为布尔型
    • 布尔型无法参与数值运算,也无法与其他类型转换
  2. 示例代码

    var flag bool
    fmt.Printf("布尔类型的默认值=%v,类型=%T\n", flag, flag) // 输出:布尔类型的默认值=false,类型=bool
    
    num := 1
    flag = bool(num) // 报错
    if num { // 报错
        fmt.Println("num为真")
    }
    
    str := "hello"
    flag = bool(str) // 报错
    if str { // 报错
        fmt.Println("str为真")
    }
    
2.3.4 字符串

字符串的值用双引号 "" 或反引号 `` 包裹。

  1. 注意事项

    • 双引号用于表示单行字符串,支持转义符。
    • 反引号用于表示多行字符串,原样输出内容,不解析转义符。
    • 单引号 '' 用于表示字符,而非字符串。
  2. 字符串转义符

    常见转义符如下表:

    转义符含义
    \r回车符
    \n换行符
    \t制表符
    \'单引号
    \"双引号
    \\反斜杠

    示例代码

    str := "mumu: \"hello golang\""
    fmt.Println(str) // 输出:mumu: "hello golang"
    
  3. 多行字符串

    Go 语言中要定义一个多行字符串时,就必须使用反引号。

    multiLine := `这是第一行
    这是第二行
    	这是带缩进的第三行
    这是第四行`
    	fmt.Println(multiLine)
    // 这是第一行
    // 这是第二行
    //         这是带缩进的第三行
    // 这是第四行
    
  4. 字符串常用的方法

    方法功能示例
    len(str)返回字符串字节数str := "mumu"; fmt.Println(len(str)) // 输出:4
    +拼接字符串fmt.Println("hello" + " golang") // 输出:hello golang
    fmt.Sprintf格式化拼接字符串str1:="hello";str2:="golang";str3:=fmt.Sprintf("%v %v",str1,str2) // str3为hello golang
    strings.Split(str, sep)按分隔符分割字符串,返回切片str:="hello golang";arr:=strings.Split(str," ");fmt.Println(arr) // 输出:[hello golang]
    strings.Join(arr, sep)将切片按分隔符合并为字符串arr:=[]string{"hello","golang"};str:=strings.Join(arr,"-");fmt.Println(str) // 输出:hello-golang
    strings.Contains(str1, str2)判断 str1 是否包含 str2str1:="hello golang";str2:="ello";fmt.Println(strings.Contains(str1,str2)) // 输出:true
    strings.HasPrefix(str1, str2)判断 str1 是否以 str2 开头str1:="hello golang";str2:="hello";fmt.Println(strings.HasPrefix(str1,str2)) // 输出:true
    strings.HasSuffix(str1, str2)判断 str1 是否以 str2 结尾str1:="hello golang";str2:="golang";fmt.Println(strings.HasSuffix(str1,str2)) // 输出:true
    strings.Index(str, substr)查找 substr 在 str 中首次出现的索引,不存在返回 -1fmt.Println(strings.Index("hello golang","golang")) // 输出:6
    strings.LastIndex(str, substr)查找 substr 在 str 中最后出现的索引,不存在返回 -1fmt.Println(strings.LastIndex("hello golang","an")) // 输出:9
2.3.5 byte & rune

byterune 是 Go 语言中用于表示字符的专属类型,底层都是整型的别名。

  1. byte 与 rune 的区别

    类型底层类型占用字节适用场景
    byteuint81表示 ASCII 字符(0-127 范围)
    runeint324表示 Unicode 字符(如中文、emoji 等)
  2. 字符串遍历

    • for i 循环遍历(按字节)

      Go 字符串底层是字节数组,for i 循环遍历的是每个字节的值。

      s := "Hello 世界"
      for i := 0; i < len(s); i++ {
          fmt.Printf("%x ", s[i]) // 输出:48 65 6c 6c 6f 20 e4 b8 96 e7 95 8c
      }
      
    • for range 遍历(按 rune)

      for range 会自动将字符串按 Unicode 字符拆分,遍历的是 rune 类型的值。

      s := "Hello 世界"
      for _, r := range s {
          fmt.Printf("%c ", r) // 输出:H e l l o  世 界
      }
      
  3. 字符串长度计算

    • len (str):返回字节数

      对于包含多字节字符的字符串,字节数大于字符数。

      str:= "go 你好"
      fmt.Println(len(str)) // 输出:9(go占2字节,空格占1,你好各占3,共2+1+3+3=9)
      
    • len ([] rune (str)):返回字符数

      将字符串转为 rune 切片后,再计算长度即可得到字符数。

      str:= "go 你好"
      fmt.Println(len([]rune(str))) // 输出:5
      
    • utf8.RuneCountInString (str):返回字符数

      使用 unicode/utf8 包的函数直接获取字符数。

      str:= "go 你好"
      fmt.Println(utf8.RuneCountInString(str)) // 输出:5
      

持续更新中...