语言要求

格式化:Go 官方对语言风格本身是强行要求的,所以不用管。 错误处理:Go 没有异常机制(try-catch),习惯 if err != nil,不要忽略错误。 关于分号:Go 的源码里基本看不到分号,编译器会在换行时自动加,所以不要手欠自己加分号。

依赖管理

现在都用 Go Modules:

可见性

Go 没有 publicprivate 关键字,全靠首字母大小写控制访问权限:

类型

基础类型

类型描述默认值(Zero Value)
bool布尔型false
string字符串(不可变,UTF-8)""(空串)
int, int64整型(int 随系统位数变化)0
uint, uint64无符号整型0
float32, float64浮点型0.0
byteuint8 的别名(存 ASCII)0
runeint32 的别名(存 Unicode)0
complex64, complex128复数(0+0i)
nil指针、切片、Map、接口、通道的零值nil

重要:Go 没有“未初始化”的变量,所有变量声明后都会被赋予零值。

指针

和 C 类似,但不支持指针运算(不能 p++)。

i := 42
p := &i         // 取地址
fmt.Println(*p) // 取值
*p = 21         // 修改值

变量和常量

Go 是强类型语言,但支持类型推导。声明了变量但没使用,编译会报错。常量大部分规则等同于变量

var a int = 10         // 标准声明
var b = 20             // 类型推导(自动识别为int)
c := 30                // 短变量声明(语法糖,只能在函数内部使用)

// 多变量声明
var x, y int = 1, 2
name, age := "Alice", 18

// 常量
const c int = 100
const big = 1 << 10 // 编译期计算

复合数据结构

数组

长度固定,是值类型。

var a [5]int            // [0 0 0 0 0]
b := [3]int{1, 2, 3}    // 初始化
c := [...]int{4, 5, 6}  // 自动推导长度
d := b                  // 会拷贝整个数组

切片

切片是对数组的动态视图,长度可变,引用类型。

切片截取后底层数组是共享的,修改子切片会影响原切片,除非发生扩容导致内存重新分配。

// 声明
var s []int             // nil 切片
s := []int{1, 2, 3}
s := make([]int, 5, 10) // make(类型, 长度, 容量),会建立一个底层数组,然后返回切片

// 操作
s = append(s, 4)        // 追加元素(可能会触发扩容)
sub := s[1:3]           // 切片操作 [startIndex : endIndex] (左闭右开)

Map

无序的键值对,引用类型。

// 初始化
m := make(map[string]int) // 这里是初始化
m := make(map[string]int, 100) 
m["one"] = 1

// 字面量
scores := map[string]int{
    "Alice": 100,
    "Bob":   98,
}

// 查找
v, ok := scores["Charlie"] // 这里的 ok 模式非常经典
if ok {
    fmt.Println("存在:", v)
} else {
    fmt.Println("不存在")
}

delete(scores, "Bob") // 删除

结构体

Go 没有 class,只有 struct。没有继承,只有组合(Embedding)。

type User struct {
    Name string `json:"name"` // 后面是 Tag,用于 JSON 解析等
    Age  int
}

// 匿名结构体
u := struct {
    x, y int
}{1, 2}

// 组合(类似继承)
type Admin struct {
    User  // 匿名字段,Admin 直接拥有 User 的字段
    Level int
}

iota 枚举生成器

// iota 枚举生成器
const (
    A = iota // 0
    B        // 1 (自动递增)
    C        // 2
    _        // 跳过 3
    E        // 4
)

运算符

基本和 C/Python 一样,除了以下几点

控制流

// if
if x > 0 {
    // ...
} else {
    // ...
}

// 带初始化的 if(scope 限制在 if 块内)
if err := compute(); err != nil {
    fmt.Println(err)
    return
}

// for
// 标准循环
for i := 0; i < 10; i++ { }

// 类似 while
for i < 10 { }

// 死循环
for { }

// Range 遍历(最常用)
nums := []int{2, 3, 4}
for i, v := range nums { // i 是索引, v 是值的拷贝
    fmt.Printf("Index: %d, Value: %d\n", i, v)
}
// 如果不需要索引,用 _ 丢弃
for _, v := range nums { }

// switch
switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X")
case "linux":
    fmt.Println("Linux")
default:
    fmt.Println("Other")
}

函数

支持多返回值,函数是一等公民,定义如下:

func add(a, b int) (int, error) {
    if a < 0 {
        return 0, errors.New("negative")
    }
    return a + b, nil
}

res, err := add(1, 2)

Go 中有 Defer(延迟执行)这个特殊语法,用来让代码在函数返回前执行,常用于资源释放(关闭文件、锁)。执行顺序:先进后出(栈)。

func readFile() {
    f, _ := os.Open("file.txt")
    defer f.Close() // 无论下面发生什么,函数退出前一定会 Close

    // Do something...
}

面向对象

方法

方法是附着在特定类型上的函数。通过接收者(Receiver)定义。

type Rect struct{ w, h int }

// 值接收者(不修改原对象)
func (r Rect) Area() int {
    return r.w * r.h
}

// 指针接收者(修改原对象,或者对象很大时节省拷贝)
func (r *Rect) Scale(f int) {
    r.w *= f
    r.h *= f
}

接口

Go 的接口是隐式实现的(Duck Typing)。只要你实现了接口里的所有方法,你就实现了该接口,不需要显式写 implements

// 声明
type Shape interface {
    Area() float64

}

// 构造
type Rect struct {
    Width, Height float64
}
// Rect 有一个方法 Area(),签名和 Shape 要求的一模一样
func (r Rect) Area() float64 {
    return r.Width * r.Height
}
// 只要 Rect 实现了 Area(),它就是 Shape
var s Shape = &Rect{10, 5}

// 空接口 interface{}
// 代表任意类型(类似 C 的 void* 或 Python 的 object)
// Go 1.18 后可以使用别名 any 替换 interface{}
func printAny(v interface{}) {
    fmt.Println(v)
}

类型断言

猜变量类型。如果猜对了,val 就是那个 int 值,ok 为 true;如果猜错了,ok 为 false,val 为 int 零值,不会 panic。

val, ok := v.(int) 

并发编程

口号:不要通过共享内存来通信,要通过通信来共享内存。

Goroutine

轻量级线程,启动成本极低。

go func() {
    fmt.Println("I'm running in background")
}()

Channel(通道)

用于 Goroutine 之间传递数据。

ch := make(chan int)    // 无缓冲通道
ch := make(chan int, 3) // 有缓冲通道

// 发送
ch <- 42

// 接收
val := <-ch

// 关闭
close(ch)

Select

多路复用,监听多个 Channel。

select {
case msg1 := <-c1:
    fmt.Println(msg1)
case msg2 := <-c2:
    fmt.Println(msg2)
case <-time.After(time.Second):
    fmt.Println("Timeout")
}

常用库函数

fmt

函数说明
Print / Println标准输出
Printf格式化输出
Sprintf格式化并返回字符串
Errorf格式化并返回 error

常用占位符:

strings

函数说明
Contains(s, substr)是否包含
Split(s, sep)切割
Join(a, sep)拼接
TrimSpace(s)去除首尾空白
ReplaceAll(s, old, new)替换

strconv (字符串转换)

函数说明
Atoi(s)stringint
Itoa(i)intstring
ParseFloat(s, 64)stringfloat64

encoding/json

函数说明
Marshal(v)结构体/Map → JSON 字节切片
Unmarshal(data, &v)JSON 字节切片 → 结构体/Map

Tag 用法:

type User struct {
    Name string `json:"username"`         // 重命名 Key
    Age  int    `json:"age,omitempty"`    // 如果是 0 值则忽略
    Pwd  string `json:"-"`                // 永远忽略
}