6.5. 匿名结构体

在本章前几节中,我们使用到的结构体都是按以下形式声明的:

type 类型名 struct {
    成员列表
}

实际上该语法的内在含义是:

  1. struct {...} 的部分定义了一个结构体;
  2. type 类型名 的部分为刚才定义的结构体赋予了一个名字。

那么在凹语言中,是否可以通过声明结构体字面量的方式直接创建一个结构体变量,而无需对该结构体命名?确实是可以的,这种用法被称为匿名结构体,例如:

// 版权 @2021 凹语言 作者。保留所有权利。

//全局匿名结构体变量:
global G: struct{
    name: string
    age: i32
}

func main {
    G.name = "张三"
    G.age = 88
    println(G.name, " ", G.age)  // 张三 88

    //局部匿名结构体变量:
    k := struct {name: string; age: i32}{name: "李四", age: 66}
    println(k.name, " ", k.age)  // 李四 66

    G = k
    println(G.name, " ", G.age)  // 李四 66
}

由于匿名结构体没有类型名,因此声明匿名结构体变量时只能使用 变量名: struct{...} 或其快捷定义形式直接指定类型(结构体)。除此之外,匿名结构体以及其成员的使用,与普通的具名结构体基本一致。匿名结构体同样遵循0值初始化规则,其字面值中,未指定初始值的成员均为0值。

匿名结构体最常用的场景是全局配置变量。很多全局配置变量的类型,仅仅在声明该全局变量时会被使用一次,为仅存在一个实例的变量单独定义一个类型略显繁琐,此时即可使用匿名结构体替代(例如上例中的全局变量 G)。

具名类型位于模块的名字空间下,但匿名结构体因为没有名字,其定义实际上位于全局空间,因此如果两个匿名结构体变量的内存布局完全一致(既成员个数、对应成员名、对应成员类型均一致),它们将被认为属于同一个类型,可以互相赋值(例如上例中的全局变量 G 和 局部变量 k),哪怕这两个变量位于不同模块中,该特性依然成立;这引出了匿名结构体的另一个使用场景:跨模块传递参数。

由于匿名结构体没有类型名,因此按照语法规则,无法为其添加方法。