考慮一個二維的繪圖程序,提供了一個各種圖形的庫,例如矩形、橢圓形、星形和輪形等幾何形狀。這里是其中兩個的定義:
type Circle struct {
X, Y, Radius int
}
type Wheel struct {
X, Y, Radius, Spokes int
}
一個Circle代表的圓形類型包含了標准圓心的X和Y坐標信息,和一個Radius表示的半徑信息。一個Wheel輪形除了包含Circle類型所有的全部成員外,還增加了Spokes表示徑向輻條的數量。我們可以這樣創建一個wheel變量:
var w Wheel w.X = 8 w.Y = 8 w.Radius = 5 w.Spokes = 20
隨着庫中幾何形狀數量的增多,我們一定會注意到它們之間的相似和重復之處,所以我們可能為了便於維護而將相同的屬性獨立出來:
ype Point struct {
X, Y int
}
type Circle struct {
Center Point
Radius int
}
type Wheel struct {
Circle Circle
Spokes int
}
這樣改動之后結構體類型變的清晰了,但是這種修改同時也導致了訪問每個成員變得繁瑣:
var w Wheel w.Circle.Center.X = 8 w.Circle.Center.Y = 8 w.Circle.Radius = 5 w.Spokes = 20
Go語言有一個特性讓我們只聲明一個成員對應的數據類型而不指名成員的名字;這類成員就叫匿名成員。匿名成員的數據類型必須是命名的類型或指向一個命名的類型的指針。下面的代碼中,Circle和Wheel各自都有一個匿名成員。我們可以說Point類型被嵌入到了Circle結構體,同時Circle類型被嵌入到了Wheel結構體。
type Circle struct {
oint
Radius int
}
type Wheel struct {
Circle
Spokes int
}
得意於匿名嵌入的特性,我們可以直接訪問葉子屬性而不需要給出完整的路徑:
var w Wheel w.X = 8 // equivalent to w.Circle.Point.X = 8 w.Y = 8 // equivalent to w.Circle.Point.Y = 8 w.Radius = 5 // equivalent to w.Circle.Radius = 5 w.Spokes = 20
在右邊的注釋中給出的顯式形式訪問這些葉子成員的語法依然有效,因此匿名成員並不是真的無法訪問了。其中匿名成員Circle和Point都有自己的名字——就是命名的類型名字——但是這些名字在點操作符中是可選的。我們在訪問子成員的時候可以忽略任何匿名成員部分。
不幸的是,結構體字面值並沒有簡短表示匿名成員的語法, 因此下面的語句都不能編譯通過:
w = Wheel{8, 8, 5, 20} // compile error: unknown fields
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
結構體字面值必須遵循形狀類型聲明時的結構,所以我們只能用下面的兩種語法,它們彼此是等價的:
w = Wheel{Circle{Point{8, 8}, 5}, 20} w = Wheel{ Circle: Circle{ Point: Point{X:8, Y:8}, Radius: 5, }, Spokes: 20, }