Go 语言
声明、类型、语句与控制结构
复合字面值

复合字面值

Go 语言中的复合类型包括:数组、结构体、切片、map、管道和接口。复合字面值可以用来创建复合类型的常量值。对于复合类型变量,最常见的值构造方式就是对其内部元素进行逐个赋值。 但是赋值构造的方式极其繁琐,可以使复合字面值语法来改写。

type Point struct {
    X, Y int
}
p := Point{1, 2} // 结构体
a := [5]int{1, 2, 3, 4, 5} // 数组
s := []int{1, 2, 3, 4, 5} // 切片
m := map[string]int{"one": 1, "two": 2} // map

结构体复合字面值

Go 推荐使用 field: value 的复合字面值形式对 struct 类型变量进行值构造,这种值构造方式可以降低结构体类型使用者和结构体类型定义者之间的耦合度。

type pipe struct {
    wrMu sync.Mutex
    wrCh chan []byte
    rdCh chan int
 
    once sync.Once
    done chan struct{}
    rerr onceError
    werr onceError
}
 
func Pipe() (*PipeReader, *PipeWriter) {
    p := &pipe{
        wrCh: make(chan []byte),
        rdCh: make(chan int),
        done: make(chan struct{}),
    }
    return &PipeReader{p}, &PipeWriter{p}
}

数组/切片复合字面值

数组和切片的复合字面值语法相同,都是使用花括号包裹一系列以逗号分隔的元素值来初始化数组或切片的元素。其采用 index: value 为其构造初值。

var data = []int{0: -10, 1: 5, 2: 3, 3: 2, 4: 0, 5: 1, 6: 9, 7: 7, 8: 6, 9: 4}
var sdata = []string{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h", 8: "i", 9: "j"}

map 复合字面值

和结构体、数组、切片相比,map 类型变量使用复合字面值就显得自然很多,因为 map 天生具有 key: value 构造形式:

var timeZone = map[string]int{
    "UTC": 0 * 60 * 60,
    "EST": -5 * 60 * 60,
    "CST": -6 * 60 * 60,
    "MST": -7 * 60 * 60,
    "PST": -8 * 60 * 60,
}

对于数组和切片类型,其元素为复合类型时,可以省去元素类型的声明,直接使用复合字面值的简化形式:

type Point struct {
    X, Y int
}
 
var data = []Point{
    {1, 2}, // Point{1, 2}
    {3, 4}, // Point{3, 4}
}

但对于 map 来说,这一语法糖在 Go 1.5 版本之后才引入:

m := map[string]Point{
    "Bell Labs": {40, -74},
    "Google":    {37, -122},
}

对于 key 或 value 为指针类型的 map,其复合字面值形式也可以省略指针类型的声明:

var m = map[string]*Point{
    "orig": {0, 0},
    "east": {1, 0},
    "west": {0, 1},
    "north": {0, -1},
    "south": {0, 1},
}
 
println(m) // map[east:0x109be180 north:0x109be1a0 orig:0x109be160 south:0x109be1c0 west:0x109be190]