Go语言(Golang)简明语法教程

1. Hello World & 模块

// 初始化模块: go mod init example.com/m
// 运行: go run main.go
// 编译: go build main.go

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

2. 基本数据类型

bool

string // 只读的字节切片

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte   // uint8 的别名
rune   // int32 的别名,表示一个 Unicode 码点

float32 float64

complex64 complex128

3. 变量声明

// 标准声明
var a int = 10
var b = 10      // 类型推导
c := 10         // 短变量声明,仅函数内可用

```go
// 批量声明
var (
    name string = "Ada"
    age  int    = 4
    isAI bool   = true
)

变量遮蔽问题

Go允许内层变量遮蔽外层变量,这是常见陷阱。

x := 1
{
    x := 2  // 遮蔽外层 x
    fmt.Println(x) // 输出 2
}
fmt.Println(x) // 输出 1,外层不变

4. 常量

const PI = 3.14
const (
    Monday = iota // 0
    Tuesday       // 1
    Wednesday     // 2
)

5. 流程控制

if

if x := 10; x > 5 {  // 支持初始化语句
    fmt.Println("x 大于 5")
} else {
    fmt.Println("x 不大于 5")
}

for(Go 只有 for 一种循环)

// 1. 经典 for(三个语句:初始化; 条件; 后置)
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

// 2. 类似 while(只有条件)
sum := 0
for sum < 100 {
    sum += 10
}

// 3. 无限循环(没有条件)
for {
    // break 或 return 退出
}

// 4. range 遍历数组/切片
nums := []int{1, 2, 3}
for i, v := range nums {  // 索引和值
    fmt.Println(i, v)
}
for i := range nums {     // 只获取索引
    fmt.Println(i)
}
for _, v := range nums {   // 只获取值(用 _ 忽略索引)
    fmt.Println(v)
}
for range nums {           // 只迭代,不获取任何值(用于需要执行固定次数的场景)
    fmt.Println("iteration")
}

// 5. range 遍历 map
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {      // 键和值
    fmt.Println(k, v)
}
for k := range m {        // 只获取键
    fmt.Println(k)
}

// 6. range 遍历字符串(遍历 rune)
s := "你好"
for i, r := range s {     // 字节索引和 rune 值
    fmt.Printf("%d: %c\n", i, r)
}

// 7. range 遍历 channel
ch := make(chan int, 3)
ch <- 1; ch <- 2; ch <- 3
close(ch)
for v := range ch {       // 遍历直到 channel 关闭
    fmt.Println(v)
}

// 8. break 和 continue
for i := 0; i < 10; i++ {
    if i == 3 {
        continue  // 跳过本次迭代
    }
    if i == 7 {
        break     // 退出循环
    }
    fmt.Println(i)
}

// 9. label 配合 break/continue(跳出多层循环)
outer:
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if i == 1 && j == 1 {
            break outer  // 跳出外层循环
        }
        fmt.Println(i, j)
    }
}

// 10. for 初始化语句(支持短变量声明)
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
    fmt.Println(i, j)
}

switch

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("macOS")
case "linux":
    fmt.Println("Linux")
default:
    fmt.Println("Other")
}
// switch 无需 break,自动中断
// fallthrough 可继续执行下一个 case

6. 数组和切片(Slice)

// 数组(固定长度)
var arr [5]int
arr2 := [3]string{"a", "b", "c"}

// 切片(动态数组)
slice := []int{1, 2, 3}
slice = append(slice, 4)

// make 创建指定长度和容量
s := make([]int, 5, 10) // len=5, cap=10

// 切片操作
sub := slice[1:4] // 从索引1到3

slices 包(Go 1.21+)

import "slices"

// 查找元素
index := slices.Index(slice, 2) // 返回索引,不存在返回-1
contains := slices.Contains(slice, 2) // 返回bool

// 排序
slices.Sort(slice) // 升序
slices.SortFunc(slice, func(a, b int) int { return b - a }) // 自定义排序

// 反转
slices.Reverse(slice)

// 去重(需要先排序)
unique := slices.Compact(slice)

// 比较
equal := slices.Equal(slice, []int{1, 2, 3})

// 复制
copySlice := slices.Clone(slice)

// 删除元素
slice = slices.Delete(slice, 1, 3) // 删除索引1到3的元素

// 插入元素
slice = slices.Insert(slice, 1, 10, 20) // 在索引1处插入10和20

7. Map(字典)

m := make(map[string]int)
m["age"] = 18

m2 := map[string]string{"name": "Ada"}

// 检查键是否存在
value, ok := m["age"] // ok 为 bool

// 删除
delete(m, "age")

maps 包(Go 1.21+)

import "maps"

// 复制
copyMap := maps.Clone(m)

// 比较
equal := maps.Equal(m, map[string]int{"age": 18})

// 清空
maps.Clear(m)

// 合并(覆盖)
maps.Copy(m, map[string]int{"age": 20, "height": 180})

// 获取所有键
keys := maps.Keys(m)

// 获取所有值
values := maps.Values(m)

8. 函数

// 普通函数
func add(a, b int) int {
    return a + b
}

// 多返回值
func div(a, b int) (int, int) {
    return a/b, a%b
}

// 命名返回值
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return // 裸返回
}

// 可变参数
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

```go
// defer:延迟执行,常用于资源释放。在函数返回前按 LIFO 顺序执行。
func doSomething() {
    f, _ := os.Open("file.txt")
    defer f.Close()
}

// 闭包用法:函数捕获外部变量,形成闭包
func counter() func() int {
    count := 0  // 被内层函数捕获
    return func() int {
        count++
        return count
    }
}

闭包注意事项

在goroutine中使用循环变量时需注意:

nums := []int{1, 2, 3}
for _, n := range nums {
    go func(x int) {  // 传参避免问题
        fmt.Println(x)
    }(n)
}

9. 指针

var p *int
i := 42
p = &i     // 取地址
fmt.Println(*p) // 解引用

// new 函数分配内存
p2 := new(int)

基于地址的用法(指针高级)

指针常用于函数修改调用者变量,或传递大结构体避免拷贝开销。

// 函数通过指针修改外部变量
func increment(p *int) {
    *p++
}
x := 10
increment(&x)
fmt.Println(x) // 11

// 大结构体用指针接收者
type BigStruct struct {
    data [1000]int
}
func (b *BigStruct) process() {
    b.data[0] = 99
}
bs := BigStruct{}
bs.process()  // 自动取地址
fmt.Println(bs.data[0]) // 99

引用类型无需指针:切片、map、channel、函数、接口是引用,修改自动生效。

10. 类型定义 (Type)

// 1. 类型定义 (Type Definition) - 创建新类型
type MyInt int

// 2. 类型别名 (Type Alias) - 仅起别名,类型相同
type MyAlias = int

// 3. 定义函数类型
type Handler func(int) bool

11. 结构体 (Struct)

type Person struct {
    Name string `json:"name"` // 结构体标签 (Tag)
    Age  int    `json:"age"`
}

// 匿名结构体
point := struct {
    X, Y int
}{10, 20}

方法 (Methods)

func (p Person) SayHello() {  // 值接收者
    fmt.Printf("Hello, I'm %s\n", p.Name)
}

func (p *Person) Birthday() { // 指针接收者,可修改
    p.Age++
}

“继承” (组合/嵌套)

Go 语言没有类继承,通过结构体嵌套(Embedding)实现组合。

type Admin struct {
    Person // 匿名嵌套
    Level  int
}

a := Admin{
    Person: Person{Name: "Linus", Age: 50},
    Level:  1,
}
fmt.Println(a.Name) // 直接访问嵌套字段
a.SayHello()        // 直接调用嵌套方法

12. 接口

type Speaker interface {
    Speak() string
}

func Greet(s Speaker) {
    fmt.Println(s.Speak())
}

// any:空接口 interface{} 的别名,可代表任何类型
var x any = "hello"

// 类型断言
s, ok := x.(string)

// 类型 Switch
switch v := x.(type) {
case int:
    fmt.Println("int", v)
case string:
    fmt.Println("string", v)
}

13. 错误处理

func sqrt(x float64) (float64, error) {
    if x < 0 {
        return 0, errors.New("负数无平方根")
    }
    return math.Sqrt(x), nil
}

// 使用
result, err := sqrt(-1)
if err != nil {
    fmt.Println(err)
}

14. 并发:Goroutine 和 Channel

// 启动 goroutine
go func() {
    fmt.Println("我在 goroutine 中")
}()

// Channel
ch := make(chan int)
go func() {
    ch <- 42  // 发送
}()
value := <-ch // 接收

// 带缓冲 channel
ch2 := make(chan string, 2)
ch2 <- "hello"
ch2 <- "world"

// select 多路复用
select {
case msg := <-ch:
    fmt.Println(msg)
case <-time.After(1 * time.Second):
    fmt.Println("超时")
}

15. 泛型 (Generics)

// 泛型函数
func MapKeys[K comparable, V any](m map[K]V) []K {
    r := make([]K, 0, len(m))
    for k := range m {
        r = append(r, k)
    }
    return r
}

// 泛型结构体
type Stack[T any] struct {
    elements []T
}

16. init 函数

func init() {
    // 包加载时自动执行,早于 main 函数
    // 常用于初始化配置、注册驱动等
}

17. 单元测试

// 文件名必须以 _test.go 结尾
// 函数名必须以 Test 开头
func TestAdd(t *testing.T) {
    got := Add(1, 2)
    if got != 3 {
        t.Errorf("Add(1, 2) = %d; want 3", got)
    }
}

18. 常用标准库

  • fmt:格式化输入输出
  • time:时间处理
  • os / os/exec:系统操作
  • net/http:构建 Web 服务
  • encoding/json:JSON 序列化