「笔记001」Go语法基础2
一、结构体与方法
1. 结构体的基本定义与使用
结构体(struct)是 Go 描述复杂数据的核心工具,用于组织不同类型的字段。
示例代码: ```go type User struct { Name string Age int IsActive bool }
func main() { user := User{Name: "Alice", Age: 25, IsActive: true} fmt.Println(user.Name) // Alice } ```
2. 方法的定义与指针接收器
Go 不直接支持类与继承,但可以为结构体定义方法。方法可分为值接收器和指针接收器:
- 值接收器:方法作用于结构体的副本,无法修改原结构体内容。
- 指针接收器:允许修改原结构体内容。
type User struct {
Name string
Age int
}
func (u *User) IncrementAge() {
u.Age++
}
func main() {
user := User{Name: "Bob", Age: 30}
user.IncrementAge()
fmt.Println(user.Age) // 31
}
知识点讲解:
- 指针接收器推荐使用场景:结构体较大时,使用指针接收器避免不必要的内存拷贝。
- 值接收器的适用场景:仅需读取数据且无需修改结构体内容。
注意事项:
- Go 中的方法不支持重载,同一类型下的方法名必须唯一。
- 指针接收器需注意初始化问题,避免
nil
指针调用方法。
二、字符串与 Range
1. 字符串操作
Go 提供了强大的 strings
包,用于字符串处理。常用操作包括:
- 检查子串:
go fmt.Println(strings.Contains("hello", "ll")) // true
- 字符串替换:
go fmt.Println(strings.Replace("hello", "l", "L", -1)) // heLLo
- 字符串分割:
go parts := strings.Split("a,b,c", ",") fmt.Println(parts) // [a b c]
2. Range 遍历
range
是 Go 的高级遍历工具,用于字符串、数组、切片、Map 等数据结构。
go
for i, c := range "hello" {
fmt.Printf("%d: %c\n", i, c)
}
知识点讲解:
- Unicode 字符处理:
range
会自动处理 Unicode 编码,适合多语言字符串的遍历。 - 字符串不可变:Go 的字符串是不可变的,每次修改都会生成新的字符串。
注意事项:
- 对于长字符串的频繁修改,建议使用
strings.Builder
提升性能。 - 字符串分割时,确保目标字符串符合预期格式,避免索引超出范围。
三、时间处理
Go 的 time
包提供了丰富的时间操作功能,包括获取当前时间、格式化时间和计算时间差。
1. 时间获取与格式化
now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05")) // 格式化当前时间
2. 时间差计算
start := time.Now()
// 模拟耗时操作
time.Sleep(2 * time.Second)
elapsed := time.Since(start)
fmt.Println("Elapsed:", elapsed) // Elapsed: 2s
知识点讲解:
- 时间格式化规则:Go 使用固定的日期
2006-01-02 15:04:05
作为模板。 - 时间戳与 UTC:
Unix()
返回秒级时间戳,而UnixNano()
返回纳秒级时间戳。
注意事项:
- 时间运算涉及时区时需注意统一时区。
- 使用
time.Parse
解析字符串时,确保格式与模板一致。
四、JSON 处理
JSON 是现代开发中最常用的数据交换格式,Go 提供了内置的 encoding/json
包处理 JSON 数据。
1. JSON 序列化与反序列化
结构体序列化:
``go type User struct { Name string
json:"name"Age int
json:"age"` }user := User{Name: "Alice", Age: 25} jsonData, _ := json.Marshal(user) fmt.Println(string(jsonData)) // {"name":"Alice","age":25} ```
结构体反序列化:
go var decoded User json.Unmarshal([]byte(`{"name":"Alice","age":25}`), &decoded) fmt.Println(decoded.Name) // Alice
知识点讲解:
- JSON 标签:结构体字段名与 JSON 字段映射通过
json
标签控制,标签区分大小写。 - 嵌套结构体:嵌套结构体的字段需确保 JSON 标签完整匹配。
注意事项:
- 字段首字母必须大写以导出为 JSON,否则会被忽略。
- JSON 字符串中的字段值类型需与结构体字段类型一致。
五、协程与通道
1. 协程(Goroutine)
Go 原生支持轻量级线程,协程的启动使用 go
关键字。
go
go func() {
fmt.Println("Hello, Goroutine!")
}()
2. 通道(Channel)
通道是协程间通信的桥梁,支持无缓冲和缓冲两种模式:
go
ch := make(chan int)
go func() { ch <- 42 }()
fmt.Println(<-ch) // 42
3. Select 多路复用
select
监听多个通道操作:
go
select {
case msg := <-ch1:
fmt.Println("Received", msg)
case msg := <-ch2:
fmt.Println("Received", msg)
default:
fmt.Println("No message received")
}
知识点讲解:
- 无缓冲通道:数据发送和接收必须同时进行。
- 缓冲通道:允许在通道中存储一定数量的数据,发送方不必立即等待接收方。
- 协程泄漏:确保协程退出时适当关闭通道,避免资源泄漏。
注意事项:
- 使用通道时需避免死锁,确保有对应的接收方。
select
的default
分支可避免通道阻塞,但需谨慎使用。
六、文件与 IO 操作
1. 文件读写
Go 的 os
包提供了文件读写的基础操作:
写文件: ```go file, err := os.Create("example.txt") if err != nil { fmt.Println("Error:", err) return } defer file.Close()
file.WriteString("Hello, Go!") ```
读文件:
go data, err := os.ReadFile("example.txt") fmt.Println(string(data)) // Hello, Go!
2. 缓冲 IO
bufio
包提供了高效的文件读取方式:
```go
file, _ := os.Open("example.txt")
defer file.Close()
scanner := bufio.NewScanner(file) for scanner.Scan() { fmt.Println(scanner.Text()) } ```
注意事项:
- 确保文件操作前后正确关闭文件,避免资源泄漏。
- 使用缓冲 IO 时需检查
scanner.Err()
以捕获可能的错误。
注意事项总结
- 结构体与方法:指针接收器适用于修改内容或避免拷贝,值接收器适合只读操作。
- 字符串与 Unicode:Go 原生支持 Unicode 编码,遍历和操作时应注意字符与字节的区别。
- 协程与通道:通道是协程通信的核心,需妥善管理通道的关闭和缓冲容量,避免死锁或资源竞争。
- 文件操作:使用
defer
确保文件资源被正确释放,避免文件句柄泄漏。 - JSON 标签规范:结构体字段必须导出,JSON 标签需匹配字段格式,注意类型一致性。