Go基础语法总结2 | 豆包MarsCode AI刷题

55 阅读5分钟

一、结构体与方法

1. 结构体的基本定义与使用

结构体(struct)是 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 包,用于字符串处理。常用操作包括:

  • 检查子串
    fmt.Println(strings.Contains("hello", "ll")) // true
    
  • 字符串替换
    fmt.Println(strings.Replace("hello", "l", "L", -1)) // heLLo
    
  • 字符串分割
    parts := strings.Split("a,b,c", ",")
    fmt.Println(parts) // [a b c]
    

2. Range 遍历

range 是 Go 的高级遍历工具,用于字符串、数组、切片、Map 等数据结构。

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 作为模板。
  • 时间戳与 UTCUnix() 返回秒级时间戳,而 UnixNano() 返回纳秒级时间戳。

注意事项:

  • 时间运算涉及时区时需注意统一时区。
  • 使用 time.Parse 解析字符串时,确保格式与模板一致。

四、JSON 处理

JSON 是现代开发中最常用的数据交换格式,Go 提供了内置的 encoding/json 包处理 JSON 数据。

1. JSON 序列化与反序列化

  • 结构体序列化
    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}
    
  • 结构体反序列化
    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 func() {
    fmt.Println("Hello, Goroutine!")
}()

2. 通道(Channel)

通道是协程间通信的桥梁,支持无缓冲和缓冲两种模式:

ch := make(chan int)
go func() { ch <- 42 }()
fmt.Println(<-ch) // 42

3. Select 多路复用

select 监听多个通道操作:

select {
case msg := <-ch1:
    fmt.Println("Received", msg)
case msg := <-ch2:
    fmt.Println("Received", msg)
default:
    fmt.Println("No message received")
}

知识点讲解:

  • 无缓冲通道:数据发送和接收必须同时进行。
  • 缓冲通道:允许在通道中存储一定数量的数据,发送方不必立即等待接收方。
  • 协程泄漏:确保协程退出时适当关闭通道,避免资源泄漏。

注意事项:

  • 使用通道时需避免死锁,确保有对应的接收方。
  • selectdefault 分支可避免通道阻塞,但需谨慎使用。

六、文件与 IO 操作

1. 文件读写

Go 的 os 包提供了文件读写的基础操作:

  • 写文件
    file, err := os.Create("example.txt")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer file.Close()
    
    file.WriteString("Hello, Go!")
    
  • 读文件
    data, err := os.ReadFile("example.txt")
    fmt.Println(string(data)) // Hello, Go!
    

2. 缓冲 IO

bufio 包提供了高效的文件读取方式:

file, _ := os.Open("example.txt")
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

注意事项:

  • 确保文件操作前后正确关闭文件,避免资源泄漏。
  • 使用缓冲 IO 时需检查 scanner.Err() 以捕获可能的错误。

注意事项总结

  1. 结构体与方法:指针接收器适用于修改内容或避免拷贝,值接收器适合只读操作。
  2. 字符串与 Unicode:Go 原生支持 Unicode 编码,遍历和操作时应注意字符与字节的区别。
  3. 协程与通道:通道是协程通信的核心,需妥善管理通道的关闭和缓冲容量,避免死锁或资源竞争。
  4. 文件操作:使用 defer 确保文件资源被正确释放,避免文件句柄泄漏。
  5. JSON 标签规范:结构体字段必须导出,JSON 标签需匹配字段格式,注意类型一致性。