這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
聲明一個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,}