声明一个struct
声明一个 struct 的语法如下:
type struct_name struct {
body
}
例如:
type Person struct {
name string
age uint8
}
关于 struct 字段的可见性
如果一个 struct 的字段以大写字母开头, 则表示这个字段是导出的, 即可以在其他包中访问这个字段, 例如:
type Person struct {
Name string
age uint8
}
上面的例子中, 因为 Person 的 Name 字段是大写字母开头, 因此可以在其他包访问它, 而 age 是小写字母开头, 因此仅仅能在包内访问.
struct 字面量
我们可以使用 struct 字面量来实例化一个 struct, 例如:
xys := Person {
"xys",
18,
}
fmt.Printf("%v\n", xys)
上面的例子中, 我们在使用 struct 字面量时, 没有指定字段的对应关系, 因此字面量中值的顺序需要和定义 struct 时的字段顺序一致, 并且不能省略任何字段. 如果顺序不对的话, 则会产生编译错误
xys := Person {
18,
"xys",
}
fmt.Printf("%v\n", xys)
上面的代码会产生编译错误, 提示类型不匹配:
src/github.com/yongshun/test.go:14: cannot use 18 (type int) as type string in field value
src/github.com/yongshun/test.go:15: cannot use "xys" (type string) as type uint8 in field value
除了上面的字面量实例化 struct 以外, 我们还可以使用另一种类型的字面量:
xys := Person{
age: 18,
name: "xys",
}
fmt.Printf("%v\n", xys)
第二种字面量初始化的方式和第一种的区别就是: 第二种需要指定字段的名字和其对应的值. 不过第二种字面量初始化方式有一个优点, 即它可以按照任意顺序排列字段, 而且可以仅仅初始化一部分的字段, 例如:
xys := Person{
name: "xys",
}
当某些字段没有被初始化时, 它的值就被初始化为默认值(这里 age 字段的默认值就是0).
注意, 这两种初始化方式不能混合使用.
struct 的比较
如果在 struct 中所有的字段都可以比较(comparable), 则这个 struct 就可以比较
p1 := Person{
age: 18,
name: "xys",
}
p2 := Person{
age: 18,
name: "xys",
}
fmt.Printf("%t\n", p1 == p2) // true
如果一个 struct 是可比较的, 则这个 struct 可以作为一个 map 的 Key, 例如:
p1 := Person{
age: 18,
name: "xys",
}
p2 := Person{
age: 18,
name: "xys",
}
fmt.Printf("%t\n", p1 == p2)
persons := make(map[Person]string)
persons[p1] = "xys"
persons[p2] = "by"
fmt.Println(persons[p1])
注意, 如果以 struct 为 key, 当两个 struct 相等, 那么对 map 来说, 这两个 struct 是同一个 key.
例如上面的例子, p1 == p2, 因此 persons[p1] == persons[p2]
struct 嵌入 与 匿名字段
Go 允许我们声明一个仅仅有类型, 但是没有名字的字段, 这样的字段叫做匿名字段.
例如:
type Person struct {
name string
age uint8
}
type Student struct {
Person
id uint32
}
上面的例子中, Student 中嵌入了另一个 struct, 即 Person, 因此 构成了一个匿名字段.
当一个 struct A 嵌入到另一个 struct B 中, 那么 struct B 就可以直接方法 struct A 中的字段.例如:
type Person struct {
name string
age uint8
}
type Student struct {
Person
id uint32
}
func main() {
var s Student
s.name = "xys"
s.age = 18
s.id = 1
fmt.Println(s)
}
上面的例子中, 我们使用 s.name 来访问了 Person 中的字段, 它等同于 "s.Person.name".
当然, 我们也可以使用字面量来初始化 Student, 例如:
s := Student {
Person: Person {
name: "xys",
age: 18,
},
id: 1,
}
根据上面的例子, 我们知道, 匿名字段其实也是有名字的, 不过它的名字是类型名, 并且在 点号表达式(dot expressions) 中, 匿名字段的类型名可以省略.
但是需要注意的是, 在字面量实例化 struct 时, 不能省略匿名字段的类型名, 即如下代码是错误的:
s := Student {
name: "xys",
age: 18,
id: 1,
}
有疑问加站长微信联系(非本文作者)