复合字面值
复合字面值能为结构体、数组、切片和 map 初始化值。它每次只能创建一个值。字面值由一个字面值类型和使用括号括起来的元素列表组成。元素前也可以声明元素对应的键。
CompositeLit = LiteralType LiteralValue .
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
SliceType | MapType | TypeName .
LiteralValue = "{" [ ElementList [ "," ] ] "}" .
ElementList = KeyedElement { "," KeyedElement } .
KeyedElement = [ Key ":" ] Element .
Key = FieldName | Expression | LiteralValue .
FieldName = identifier .
Element = Expression | LiteralValue .
字面值类型的底层类型必须是一个结构体,数组,切片或 map 类型(如果没有指定类型名就会强制执行这个约束)。元素的类型和键都必须能够分配给相应的字段的元素和键类型;没有额外的类型转换。键可以表示结构体的字段名,切片和数组的索引,map 类型的键。对于 map 字面值,所有的元素都必须有键。如果相同字段名或常量值的键对应多个元素就会报错。如果 map 类型的键为非常量类型,请看求值顺序章节。
结构体字面值遵循以下规则:
在结构体中,键必须是它的字段名。
不包含任何键的元素列表的顺序需要与结构体字段的声明顺序相同。
如果一个元素指定了键,那么所有的元素都必须指定键。
包含键的元素列表不需要指定结构体的每个字字段,缺省字段会使用字段类型的零值。
字面值可以不指定元素;这样的字面值等于该类型的零值。
指定非本包的非导出字段会报错。
给定声明:
type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }
我们可以使用这种写法:
origin := Point3D{} // Point3D 的零值
line := Line{origin, Point3D{y: -4, z: 12.3}} // line.q.x 的零值
数组和切片遵循以下规则:
每个元素都关联一个数字索引标记元素再数组中的位置。
给元素指定的键会作为它的索引。键必须是能够表示非负的
int
类型值的常量;如果是指定类型的常量,那么常量必须是整型。元素没有指定键时会使用之前的索引加一。如果第一个元素没有指定键,它的索引为零。
对复合字面值取址会生成指向由字面量初始化的变量的指针。
var pointer *Point3D = &Point3D{y: 1000}
数组字面值需要在类型中指定数组的长度。如果提供的元素少于数组的长度,那么缺少元素的位置将会使用元素类型的零值替代。如果索引超过数组的长度会报错。 …
表示数组的长度等于最大元素索引加一。
buffer := [10]string{} // len(buffer) == 10
intSet := [6]int{1, 2, 3, 5} // len(intSet) == 6
days := [...]string{"Sat", "Sun"} // len(days) == 2
切片字面值底层其实就是数组字面值。因此它的长度和容量都是元素的最大索引加一。切片字面值的格式为:
[]T{x1, x2, … xn}
可以在数组上进行切片操作从而获得切片:
tmp := [n]T{x1, x2, … xn}
tmp[0 : n]
在一个数组、切片或 map 类型 T 中。元素或者 map 的键可能有自己的字面值类型,如果字面值类型和元素或者键类型相同,那么对应的类型标识符可以省略。与之类似,如果元素或键的类型为 *T
,那么它们的 &T
也可以省略。
[...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
[][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}}
map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"}
type PPoint *Point
[2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}}
[2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
当复合字面值使用字面值类型的类型名格式出现在 if
、 for
或 switch
语句的关键字和括号之间并且没有使用圆括号包裹的时候,会引发语法歧义。在这种特殊的情况下字面值的括号会被认为是语句的代码块。为了避免歧义,复合字面值必须用括号括起来。
if x == (T{a,b,c}[i]) { … }
if (x == T{a,b,c}[i]) { … }
下面是合法的数组、切片和 map 的例子:
// list of prime numbers
primes := []int{2, 3, 5, 7, 9, 2147483647}
// vowels[ch] is true if ch is a vowel
vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}
// the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1}
filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1}
// frequencies in Hz for equal-tempered scale (A4 = 440Hz)
noteFrequency := map[string]float32{
"C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
"G0": 24.50, "A0": 27.50, "B0": 30.87,
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论