Go 语言基础学习文档
一、环境搭建
1.1 下载与安装
- 官方下载地址: golang.org/dl/
- 官方镜像站(推荐): golang.google.cn/dl/
- 安装方式:傻瓜式安装(按提示下一步即可完成)
1.2 安装验证
- 验证有没有安装成功
go version
#Go打印输出类似”go version go1.24.2 windows/amd64“,说明安装成功。
- 查看 Go 环境
go env
Go1.11 版本之后无需手动配置环境变量,使用 go mod 管理项目,也不需要非得把项目放到 GOPATH 目录下,你可以在任意位置新建项目。
Go1.13 后来可以彻底不要 GOPATH 了。
1.3 开发工具
- 推荐使用 VSCode
- 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 语言支持两种声明方式。
- 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 )
- 短变量声明法
- 适用范围:仅用于函数内部的局部变量。
- 基本用法
// 声明变量并赋值
a := "a"
// 一次声明多个变量并赋值 a, b, c := "a", 1, true
2.2.2 常量
常量是恒定不变的值,定义时必须赋值。
- const 定义常量
// 声明常量并赋值
const a = "a"
// 一次性声明多个常量并赋值 const ( a = "a" b = "b" )
- 常量省略值的特性
同时声明多个常量时,若省略值,则表明和上一行的值一样。
const (
a = "a"
b
c
)
fmt.Printf("a = %v, b = %v, c = %v
", a, b, c)
// a = a, b = a, c = a
2.3 数据类型
Go 语言数据类型分为 基本数据类型 和 复合数据类型 两大类。
- 基本数据类型:整型、浮点型、布尔型、字符串
- 复合数据类型:数组、切片、结构体、函数、map、通道(channel)、接口等
2.3.1 整型 int
整型分为 有符号整型 和 无符号整型 两类,不同类型占用字节数不同。
- 声明示例
var num int = 1
fmt.Printf("num=%v,类型=%T
", num, num)
// num=1,类型=int
- 整型分类
| 类型 | 有无符号 | 位数 | 取值范围 | 备注 | | —
| 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 | 无符号 | 8 | 0 到 255(0到2^8-1) | 别名:byte | | uint16 | 无符号 | 16 | 0 到 65535(0到2^16-1) | | | uint32 | 无符号 | 32 | 0 到 4294967295(0到2^32-1) | | | uint64 | 无符号 | 64 | 0 到 18446744073709551615(0到2^64-1) | | | int | 有符号 | 系统相关 | 32位系统同 int32,64位系统同 int64 | 推荐优先使用 | | uint | 无符号 | 系统相关 | 32位系统同 uint32,64位系统同 uint64 | | | uintptr | 无符号 | 系统相关 | 足够存储指针值的无符号整数 | 用于底层编程(如指针操作) |
- 整型类型转换
不同整型之间无法直接运算,需要强制类型转换,高位转低位时需注意数据溢出。
// 不同类型直接运算报错
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
- 数字字面量格式
| 符号 | 描述 | | —
| %d | 表明十进制输出 | | %b | 表明二进制输出 | | %o | 表明八进制输出 | | %x | 表明十六进制输出 |
示例代码
num := 16
fmt.Printf("num=%v
", num) // 输出:num=16
fmt.Printf("num=%d
", num) // 输出:num=16
fmt.Printf("num=%b
", num) // 输出:num=10000
fmt.Printf("num=%o
", num) // 输出:num=20
fmt.Printf("num=%x
", num) // 输出:num=10
- 获取变量占用字节数
使用 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 语言支持两种浮点型:float32 和 float64 。
- 声明示例
// 类型推导,默认是float64
num := 3.1415926
fmt.Printf("num=%v,类型=%T
", num, num) // 输出:num=3.1415926,类型=float64
// 显式声明 float32 num1 := float32(3.1415926) fmt.Printf("num1=%v,类型=%T
", num1, num1) // 输出:num1=3.1415925,类型=float32
// 显式声明 float64 num2 := float64(3.1415926) fmt.Printf("num2=%v,类型=%T
", num2, num2) // 输出:num2=3.1415926,类型=float64
- 浮点型范围
- float32 :最大范围约为 3.4e38
- float64 :最大范围约为 1.8e308
示例代码
fmt.Println(math.MaxFloat32) // 输出:3.4028234663852886e+38
fmt.Println(math.MaxFloat64) // 输出:1.7976931348623157e+308
- 格式化输出
使用 %f 占位符输出浮点型,可指定小数位数。
num1 := 3.1415926
fmt.Printf("%v
", num1) // 输出:3.1415926
fmt.Printf("%f
", num1) // 输出:3.141593(默认保留6位,四舍五入)
fmt.Printf("%.2f
", num1) // 输出:3.14(保留2位)
fmt.Printf("%.3f
", num1) // 输出:3.142(保留3位)
- 科学计数法
浮点型支持科学计数法表明。
num1 := 3.14e2
fmt.Printf("num1=%v,类型=%T
", num1, num1) // 输出:num1=314,类型=float64
num2 := 3.14e-2 fmt.Printf("num2=%v,类型=%T
", num2, num2) // 输出:num2=0.0314,类型=float64
- 精度丢失问题
二进制浮点数转换为十进制时可能存在精度丢失,可使用第三方包
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
- 浮点型与整型转换
- 整型转浮点型:直接强制转换,不会丢失数据
num1 := 3
num2 := float32(num1)
fmt.Printf("num2=%v,类型=%T
", num2, num2) // 输出:num2=3,类型=float32
num3 := float64(num1) fmt.Printf("num3=%v,类型=%T
", num3, num3) // 输出:num3=3,类型=float64
- 浮点型转整型:强制转换会丢失小数部分
num1 := 3.14
num2 := int(num1)
fmt.Printf("num2=%v,类型=%T
", num2, num2) // 输出:num2=3,类型=int
2.3.2 布尔类型 bool
布尔型用 bool 表明,只有 true 和 false 两个值。
- 注意事项
- 布尔型变量默认值为 false
- 不允许将整型强制转换为布尔型
- 布尔型无法参与数值运算,也无法与其他类型转换
- 示例代码
var flag bool
fmt.Printf("布尔类型的默认值=%v,类型=%T
", 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 字符串
字符串的值用双引号 “” 或反引号 ` “` 包裹。
- 注意事项
- 双引号用于表明单行字符串,支持转义符。
- 反引号用于表明多行字符串,原样输出内容,不解析转义符。
- 单引号 '' 用于表明字符,而非字符串。
- 字符串转义符
常见转义符如下表:
| 转义符 | 含义 | | —
|
| 回车符 | |
| 换行符 | | | 制表符 | | ' | 单引号 | | ” | 双引号 | | | 反斜杠 |
示例代码
str := "mumu: "hello golang""
fmt.Println(str) // 输出:mumu: "hello golang"
- 多行字符串
Go 语言中要定义一个多行字符串时,就必须使用反引号。
multiLine := `这是第一行
这是第二行
这是带缩进的第三行
这是第四行`
fmt.Println(multiLine)
// 这是第一行
// 这是第二行
// 这是带缩进的第三行
// 这是第四行
- 字符串常用的方法
| 方法 | 功能 | 示例 | | —
| len(str) | 返回字符串字节数 | str := “mumu”; fmt.Println(len(str)) // 输出:4 | | +
| 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 是否包含 str2 | str1:=”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 中首次出现的索引,不存在返回 -1 | fmt.Println(strings.Index(“hello golang”,”golang”)) // 输出:6 | | strings.LastIndex(str, substr) | 查找 substr 在 str 中最后出现的索引,不存在返回 -1 | fmt.Println(strings.LastIndex(“hello golang”,”an”)) // 输出:9 |
2.3.5 byte & rune
byte 和 rune 是 Go 语言中用于表明字符的专属类型,底层都是整型的别名。
- byte 与 rune 的区别
| 类型 | 底层类型 | 占用字节 | 适用场景 | | —
| byte | uint8 | 1 | 表明 ASCII 字符(0-127 范围) | | rune | int32 | 4 | 表明 Unicode 字符(如中文、emoji 等) |
- 字符串遍历
- 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 世 界
}
- 字符串长度计算
- 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
- 修改字符串
修改字符串,需要将其转换成 []rune 或者 []byte ,完成后再转换成 string 。无论哪种转换,都会重新分配内存,并复制字节数组。
s := "abc"
byteStr := []byte(s)
byteStr[0] = 'A'
fmt.Println(string(byteStr)) // Abc
s2 := "你好 goland" runeStr := []rune(s2) runeStr[0] = '我' fmt.Println(string(runeStr)) // 我好 goland
2.3.6 基本数据类型之间的转换
- 数值类型之间的转换
数值类型包括:整形、浮点型
// 整形与整形之间的转换(错误)
var a int8 = 1
var b int16 = 2
var c = a +
fmt.Printf("%v(%T)", c, c)
// 整形与整形之间的转换(正确) var a int8 = 1 var b int16 = 2 var c = int16(a) +
fmt.Printf("%v(%T)", c, c) // 3(int16)
// 浮点型与浮点型之间的转换(错误) var a float32 = 1 var b float64 = 2 var c = a +
fmt.Printf("%v(%T)", c, c)
// 浮点型与浮点型之间的转换(正确) var a float32 = 1 var b float64 = 2 var c = float64(a) +
fmt.Printf("%v(%T)", c, c) // 3(float64)
// 整形与浮点型之间的转换(错误) var a int32 = 1 var b float32 = 2 var c = a +
fmt.Printf("%v(%T)", c, c)
// 整形与浮点型之间的转换(正确) var a int32 = 1 var b float32 = 2 var c = float32(a) +
fmt.Printf("%v(%T)", c, c) // 3(float32)
注意:转换的时候,提议从低位转换成高位,高位转换成低位不成功就会溢出。
- 其他类型转换成 String 类型
持续更新中…





