返回介绍

复合字面值

发布于 2024-10-12 12:51:51 字数 4047 浏览 0 评论 0 收藏 0

复合字面值能为结构体、数组、切片和 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{})}

当复合字面值使用字面值类型的类型名格式出现在 ifforswitch 语句的关键字和括号之间并且没有使用圆括号包裹的时候,会引发语法歧义。在这种特殊的情况下字面值的括号会被认为是语句的代码块。为了避免歧义,复合字面值必须用括号括起来。

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文