Go 编程学习笔记

1. 变量与常量

在 Go 中,变量使用 var 声明,常量使用 const 声明。

var name = "Alice"   // 变量
const age = 30       // 常量

注意事项:常量的值在编译时必须确定,变量可以使用短变量声明 :=

2. 数据类型

Go 中的基础数据类型包括 intfloat64stringbool

var height float64 = 1.75
var isStudent bool = true

易错点:Go 是强类型语言,不同类型之间不能直接转换。

3. 条件语句

Go 中的条件语句有 ifelseswitch

if age > 18 {
    fmt.Println("Adult")
} else {
    fmt.Println("Minor")
}

注意事项:Go 中的条件不需要圆括号,if 语句中可以声明变量。

4. 循环

Go 只有 for 循环,没有 while 循环。for 可以实现条件、无限和范围循环。

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

易错点: for 循环的条件为空时即为无限循环。

5. 函数

使用 func 定义函数,支持多个返回值。

func add(a int, b int) int {
    return a + b
}

注意事项:Go 函数参数类型定义可以合并,例如 func add(a, b int)

6. 结构体与接口

Go 支持结构体定义数据类型,接口用于定义行为。

type Person struct {
    Name string
    Age  int
}

type Describer interface {
    Describe() string
}

注意事项:接口是隐式实现的,任何类型只要实现接口的方法就实现了该接口。

7. 方法

方法可以定义在结构体上,使用指针接收器以允许修改。

func (p *Person) UpdateAge(newAge int) {
    p.Age = newAge
}

注意事项:方法的接收器类型定义时要一致,使用指针接收器以避免值传递。

8. 并发与 Goroutine

使用 go 关键字启动 goroutine,并使用通道(channel)进行数据通信。

func printNumber() {
    fmt.Println("Hello from goroutine!")
}

func main() {
    go printNumber()
}

注意事项:goroutine 之间的数据传递应通过 channel 进行,避免数据竞争。

9. 错误处理

Go 使用返回值而非异常处理错误,推荐模式是 if err != nil

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

注意事项:Go 中没有 try-catch,错误处理需显式处理。

高级与小众用法

延迟执行 (defer)

使用 defer 延迟函数执行直到当前函数返回,通常用于资源释放。

func main() {
    defer fmt.Println("This will print last.")
    fmt.Println("This will print first.")
}

易错点:defer 按逆序执行,因此多个 defer 会按声明顺序倒序执行。

空白标识符 (_)

Go 中的 _ 是空白标识符,用于忽略不需要的返回值。

result, _ := someFunction()

注意事项:空白标识符仅能忽略值,不会释放内存。

标签与跳转

Go 支持标签和 goto,用于在代码中跳转。

func main() {
    for i := 0; i < 5; i++ {
        if i == 3 {
            goto Skip
        }
        fmt.Println(i)
    }
    Skip:
        fmt.Println("Jumped to label")
}

注意事项:避免滥用 goto,以免导致代码难以阅读和维护。

类型断言

类型断言用于将接口转换为具体类型。

var i interface{} = "hello"
str, ok := i.(string)
if ok {
    fmt.Println("i is a string:", str)
}

易错点:类型断言失败会引发 panic,使用 , ok 检查更安全。

匿名函数与闭包

Go 支持匿名函数和闭包,可用于即用即弃的函数。

func main() {
    add := func(a, b int) int { return a + b }
    fmt.Println(add(2, 3))
}

注意事项:闭包可以捕获外部变量,但可能导致意外的变量修改。

select 语句

select 用于从多个 channel 中选择一个进行通信。

func main() {
    c1 := make(chan string)
    c2 := make(chan string)

    go func() { c1 <- "from c1" }()
    go func() { c2 <- "from c2" }()

    select {
    case msg1 := <-c1:
        fmt.Println(msg1)
    case msg2 := <-c2:
        fmt.Println(msg2)
    }
}

注意事项:所有 case 都不准备好时,select 会阻塞,可以使用 default 防止阻塞。