Go语言从基础到进阶语法详解
目录
基础语法
1. 语言基础
包与入口
Go程序由包(package)组成,每个文件必须属于一个包。可执行程序的入口是main
包中的main
函数:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go 1.24!")
}
变量声明
Go提供多种变量声明方式:
// 标准声明
var a int = 10
var b string = "hello"
// 类型推断
var c = 3.14 // float64
var d = true // bool
// 短声明(仅函数内可用)
e := "short declaration"
内置函数(Go 1.21+新增)
Go 1.21引入min
、max
和clear
三个实用内置函数:
package main
import "fmt"
func main() {
// min/max支持多种数字类型和字符串
fmt.Println(min(1, 2, 3)) // 1
fmt.Println(max(1.5, 2.5, 0.5)) // 2.5
fmt.Println(min("a", "b", "c")) // "a"(字典序)
// clear清空map或归零切片
m := map[string]int{"a": 1, "b": 2}
clear(m)
fmt.Println(m) // map[]
s := []int{1, 2, 3}
clear(s)
fmt.Println(s) // [0 0 0](长度不变)
}
2. 控制流
条件语句
Go的if语句支持初始化表达式:
if err := doSomething(); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("成功")
}
循环语句
Go只有for一种循环结构,但支持多种形式:
// 基本for循环
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// for-range遍历
nums := []int{1, 2, 3}
for idx, val := range nums {
fmt.Printf("索引: %d, 值: %d\n", idx, val)
}
// Go 1.22+整数范围遍历
for i := range 5 { // 等价于0-4
fmt.Println(i)
}
循环变量作用域(Go 1.22+)
Go 1.22修复了循环变量闭包捕获问题:
// Go 1.22前(有问题)
for i := 0; i < 3; i++ {
defer func() { fmt.Println(i) }() // 输出3次3
}
// Go 1.22+(修复后)
for i := 0; i < 3; i++ {
defer func() { fmt.Println(i) }() // 输出0, 1, 2
}
3. 函数与方法
函数定义
Go函数支持多返回值:
// 返回两个值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为0")
}
return a / b, nil
}
// 命名返回值
func calculate() (sum, product int) {
sum = 1 + 2
product = 1 * 2
return // 无需显式指定返回变量
}
方法
方法是带接收者的函数:
type Circle struct {
Radius float64
}
// 值接收者
func (c Circle) Area() float64 {
return 3.14 * c.Radius * c.Radius
}
// 指针接收者(修改接收者)
func (c *Circle) Scale(factor float64) {
c.Radius *= factor
}
4. 复合数据类型
切片(Slice)
切片是动态数组,支持自动扩容:
// 创建切片
s1 := []int{1, 2, 3}
s2 := make([]int, 5) // 长度5,容量5
s3 := make([]int, 3, 10) // 长度3,容量10
// 切片操作
s := []int{0, 1, 2, 3, 4}
sub := s[1:3] // [1, 2](左闭右开)
Go 1.21新增slices
包提供泛型操作:
import "slices"
nums := []int{3, 1, 2}
slices.Sort(nums) // [1, 2, 3]
idx := slices.Index(nums, 2) // 1(查找元素位置)
映射(Map)
Map是键值对集合:
// 创建map
m1 := map[string]int{"a": 1, "b": 2}
m2 := make(map[string]int)
// 安全访问
val, ok := m1["c"]
if ok {
fmt.Println("c的值:", val)
} else {
fmt.Println("c不存在")
}
Go 1.21新增maps
包:
import "maps"
m := map[string]int{"a": 1, "b": 2, "c": 3}
// 删除值小于2的键
maps.DeleteFunc(m, func(k string, v int) bool {
return v < 2
})
fmt.Println(m) // map[b:2 c:3]
进阶语法
1. 泛型编程
基础泛型函数
Go 1.18引入泛型,支持类型参数:
// 泛型函数:返回两个值中较小的一个
func Min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(Min(1, 2)) // 1
fmt.Println(Min(1.5, 0.5)) // 0.5
}
泛型类型
定义泛型结构体:
// 泛型链表
type List[T any] struct {
Head *Node[T]
}
type Node[T any] struct {
Val T
Next *Node[T]
}
// 泛型方法
func (l *List[T]) Append(val T) {
// ...实现逻辑...
}
泛型类型别名(Go 1.24+)
Go 1.24支持泛型类型别名:
// 定义泛型类型
type Tree[T any] struct {
Val T
Left *Tree[T]
Right *Tree[T]
}
// 泛型类型别名
type IntTree = Tree[int]
type StringTree = Tree[string]
func main() {
var it IntTree = Tree[int]{Val: 10}
var st StringTree = Tree[string]{Val: "hello"}
}
2. 并发编程
Goroutine
轻量级线程,由Go运行时管理:
func sayHello() {
fmt.Println("Hello, goroutine!")
}
func main() {
go sayHello() // 启动goroutine
time.Sleep(100 * time.Millisecond) // 等待goroutine执行
}
通道(Channel)
用于goroutine间通信:
// 创建通道
ch := make(chan int) // 无缓冲通道
ch := make(chan int, 5) // 缓冲通道,容量5
// 发送数据
go func() {
ch <- 42 // 发送数据到通道
}()
// 接收数据
val := <-ch // 从通道接收数据
fmt.Println(val) // 42
Context包
管理goroutine生命周期:
func longRunningTask(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("任务取消:", ctx.Err())
return
default:
fmt.Println("任务运行中...")
time.Sleep(1 * time.Second)
}
}
}
func main() {
// 创建带5秒超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() // 确保资源释放
go longRunningTask(ctx)
time.Sleep(10 * time.Second) // 等待超时
}
Context最佳实践:
-
使用 context.Background()
作为根上下文 -
使用 context.TODO()
标记需要后续完善的上下文 -
不要将context存储在结构体中,应作为函数参数传递
3. 错误处理
自定义错误
// 基本自定义错误
var ErrNotFound = errors.New("资源未找到")
// 带动态信息的错误
func NewValidationError(field string) error {
return fmt.Errorf("字段验证失败: %s", field)
}
// Go 1.13+错误包装
err := fmt.Errorf("读取文件失败: %w", os.ErrNotExist)
错误处理策略
// 错误判断
if errors.Is(err, os.ErrNotExist) {
// 处理文件不存在错误
}
// 错误类型断言
var validationErr *ValidationError
if errors.As(err, &validationErr) {
// 处理验证错误
}
4. 高级特性
反射(Reflect)
在运行时检查类型信息:
import "reflect"
func inspect(v interface{}) {
t := reflect.TypeOf(v)
vv := reflect.ValueOf(v)
fmt.Println("类型:", t)
fmt.Println("值:", vv)
// 调用方法(如果有)
if m := vv.MethodByName("String"); m.IsValid() {
// ...调用方法...
}
}
注意:反射会使代码复杂且影响性能,谨慎使用。
模块化开发
使用Go Modules管理依赖:
# 初始化模块
go mod init example.com/myapp
# 添加依赖
go get github.com/some/dependency@v1.2.3
# 整理依赖
go mod tidy
附录:Go版本特性对比
版本 | 重要语法特性 |
---|---|
1.18 | 泛型、模糊测试 |
1.19 | 泛型方法作用域修复 |
1.20 | 错误包装增强、unsafe包新增函数 |
1.21 | min/max/clear内置函数、slices/maps包 |
1.22 | 循环变量作用域调整、整数范围for循环 |
1.24 | 泛型类型别名、迭代器增强 |