Go 语言中的复合类型包括结构体、数组、切片和 map。
Go 提供的复合字面值(composite literals)语法可以作为复合类型变量的初值构造器。使用复合字面值上述代码可以改写成下面这样:
s := myStruct {"tony", 23}a := [5]int{13, 14, 15, 16, 17}sl := []int{23, 24, 25, 26, 27}m := map[int]string {1:"hello", 2:"gopher", 3:"!"}
1. 结构体复合字面值
Go 推荐使用 “field:value” 格式的复合字面值形式对 struct 类型变量进行值构造,这种值构造方式可以降低结构体类型使用者与结构体类型设计者之间的耦合。这也是 Go 语言的惯用法,在 Go 标准库中,通过”field:value”格式复合字面值进行结构体类型变量初值构造的例子比比皆是:
// $GOROOT/src/net/http/transport.govar DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment,DialContext: (&net.Dialer{Timeout: 30 * time.Second,KeepAlive: 30 * time.Second,DualStack: true,}).DialContext,MaxIdleConns: 100,IdleConnTimeout: 90 * time.Second,TLSHandshakeTimeout: 10 * time.Second,ExpectContinueTimeout: 1 * time.Second,}// $GOROOT/src/io/pipe.gotype pipe struct {wrMu sync.Mutex // Serializes Write operationswrCh chan []byterdCh chan intonce sync.Once // Protects closing donedone chan struct{}rerr atomicErrorwerr atomicError}func Pipe() (*PipeReader, *PipeWriter) {p := &pipe{wrCh: make(chan []byte),rdCh: make(chan int),done: make(chan struct{}),}return &PipeReader{p}, &PipeWriter{p}}
2. 数组/切片复合字面值
和结构体类型不同,数组/切片使用下标(index)作为 “field:value” 形式中 “field”,从而实现数组/切片初始元素值的高级构造形式:
numbers := [256]int{'a': 8, 'b': 7, 'c': 4, 'd': 3, 'e': 2, 'y': 1, 'x': 5}// [10]float{-1, 0, 0, 0, -0.1, -0.1, 0, 0.1, 0, -1}fnumbers := [...]float{-1, 4: -0.1, -0.1, 7:0.1, 9: -1}// $GOROOT/src/sort/search_test.govar data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}
3. map 复合字面值
和结构体、数组/切片相比,map 类型变量使用复合字面值作为初值构造器就显得自然了许多,因为 map 类型具有原生的 “key:value” 抽象形式:
// $GOROOT/src/time/format.govar unitMap = map[string]int64{"ns": int64(Nanosecond),"us": int64(Microsecond),"µs": int64(Microsecond), // U+00B5 = micro symbol"μs": int64(Microsecond), // U+03BC = Greek letter mu"ms": int64(Millisecond),"s": int64(Second),"m": int64(Minute),"h": int64(Hour),}// $GOROOT/src/net/http/server.gotype ConnState intconst (StateNew ConnState = iotaStateActiveStateIdleStateHijackedStateClosed)var stateName = map[ConnState]string{StateNew: "new",StateActive: "active",StateIdle: "idle",StateHijacked: "hijacked",StateClosed: "closed",}
对于数组/切片类型而言,当元素的类型为复合类型时,我们可以省去元素复合字面量中的类型,比如:
type Point struct {x float64y float64}sl := []Point{{1.2345, 6.2789}, // Point{1.2345, 6.2789}{2.2345, 19.2789}, // Point{2.2345, 19.2789}}
对于 map 类型而言,这一优化在 Go 1.5 中才得以引入。引入后,当 key 或 value 的类型为复合类型时,我们可以省去 key 或 value 中的复合字面量中的类型:
// Go 1.5版本之前:m := map[Point]string{Point{29.935523, 52.891566}: "Persepolis",Point{-25.352594, 131.034361}: "Uluru",Point{37.422455, -122.084306}: "Googleplex",}vs.// Go 1.5版本及之后m := map[Point]string{{29.935523, 52.891566}: "Persepolis",{-25.352594, 131.034361}: "Uluru",{37.422455, -122.084306}: "Googleplex",}m1 := map[string]Point{"Persepolis": {29.935523, 52.891566},"Uluru": {-25.352594, 131.034361},"Googleplex": {37.422455, -122.084306},}
对于 key 或 value 为指针类型的情况,我们也可以省略 “&T”:
m2 := map[string]*Point{"Persepolis": {29.935523, 52.891566}, // &Point {29.935523, 52.891566}"Uluru": {-25.352594, 131.034361}, // &Point{-25.352594, 131.034361}"Googleplex": {37.422455, -122.084306}, // &Point{37.422455, -122.084306}}fmt.Println(m2) // map[Googleplex:0xc0000ae050 Persepolis:0xc0000ae030 Uluru:0xc0000ae040]
