mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-08 00:03:26 +00:00
回到简体
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
### 4.4.3. 結構體嵌入和匿名成員
|
||||
### 4.4.3. 结构体嵌入和匿名成员
|
||||
|
||||
在本節中,我們將看到如何使用Go語言提供的不同尋常的結構體嵌入機製讓一個命名的結構體包含另一個結構體類型的匿名成員,這樣就可以通過簡單的點運算符x.f來訪問匿名成員鏈中嵌套的x.d.e.f成員。
|
||||
在本节中,我们将看到如何使用Go语言提供的不同寻常的结构体嵌入机制让一个命名的结构体包含另一个结构体类型的匿名成员,这样就可以通过简单的点运算符x.f来访问匿名成员链中嵌套的x.d.e.f成员。
|
||||
|
||||
考慮一個二維的繪圖程序,提供了一個各種圖形的庫,例如矩形、橢圓形、星形和輪形等幾何形狀。這里是其中兩個的定義:
|
||||
考虑一个二维的绘图程序,提供了一个各种图形的库,例如矩形、椭圆形、星形和轮形等几何形状。这里是其中两个的定义:
|
||||
|
||||
```Go
|
||||
type Circle struct {
|
||||
@@ -14,7 +14,7 @@ type Wheel struct {
|
||||
}
|
||||
```
|
||||
|
||||
一個Circle代表的圓形類型包含了標準圓心的X和Y坐標信息,和一個Radius表示的半徑信息。一個Wheel輪形除了包含Circle類型所有的全部成員外,還增加了Spokes表示徑向輻條的數量。我們可以這樣創建一個wheel變量:
|
||||
一个Circle代表的圆形类型包含了标准圆心的X和Y坐标信息,和一个Radius表示的半径信息。一个Wheel轮形除了包含Circle类型所有的全部成员外,还增加了Spokes表示径向辐条的数量。我们可以这样创建一个wheel变量:
|
||||
|
||||
```Go
|
||||
var w Wheel
|
||||
@@ -24,7 +24,7 @@ w.Radius = 5
|
||||
w.Spokes = 20
|
||||
```
|
||||
|
||||
隨着庫中幾何形狀數量的增多,我們一定會註意到它們之間的相似和重複之處,所以我們可能爲了便於維護而將相同的屬性獨立出來:
|
||||
随着库中几何形状数量的增多,我们一定会注意到它们之间的相似和重复之处,所以我们可能为了便于维护而将相同的属性独立出来:
|
||||
|
||||
```Go
|
||||
type Point struct {
|
||||
@@ -42,7 +42,7 @@ type Wheel struct {
|
||||
}
|
||||
```
|
||||
|
||||
這樣改動之後結構體類型變的清晰了,但是這種脩改同時也導致了訪問每個成員變得繁瑣:
|
||||
这样改动之后结构体类型变的清晰了,但是这种修改同时也导致了访问每个成员变得繁琐:
|
||||
|
||||
```Go
|
||||
var w Wheel
|
||||
@@ -52,7 +52,7 @@ w.Circle.Radius = 5
|
||||
w.Spokes = 20
|
||||
```
|
||||
|
||||
Go語言有一個特性讓我們隻聲明一個成員對應的數據類型而不指名成員的名字;這類成員就叫匿名成員。匿名成員的數據類型必須是命名的類型或指向一個命名的類型的指針。下面的代碼中,Circle和Wheel各自都有一個匿名成員。我們可以説Point類型被嵌入到了Circle結構體,同時Circle類型被嵌入到了Wheel結構體。
|
||||
Go语言有一个特性让我们只声明一个成员对应的数据类型而不指名成员的名字;这类成员就叫匿名成员。匿名成员的数据类型必须是命名的类型或指向一个命名的类型的指针。下面的代码中,Circle和Wheel各自都有一个匿名成员。我们可以说Point类型被嵌入到了Circle结构体,同时Circle类型被嵌入到了Wheel结构体。
|
||||
|
||||
```Go
|
||||
type Circle struct {
|
||||
@@ -66,7 +66,7 @@ type Wheel struct {
|
||||
}
|
||||
```
|
||||
|
||||
得意於匿名嵌入的特性,我們可以直接訪問葉子屬性而不需要給出完整的路徑:
|
||||
得意于匿名嵌入的特性,我们可以直接访问叶子属性而不需要给出完整的路径:
|
||||
|
||||
```Go
|
||||
var w Wheel
|
||||
@@ -76,16 +76,16 @@ w.Radius = 5 // equivalent to w.Circle.Radius = 5
|
||||
w.Spokes = 20
|
||||
```
|
||||
|
||||
在右邊的註釋中給出的顯式形式訪問這些葉子成員的語法依然有效,因此匿名成員併不是眞的無法訪問了。其中匿名成員Circle和Point都有自己的名字——就是命名的類型名字——但是這些名字在點操作符中是可選的。我們在訪問子成員的時候可以忽略任何匿名成員部分。
|
||||
在右边的注释中给出的显式形式访问这些叶子成员的语法依然有效,因此匿名成员并不是真的无法访问了。其中匿名成员Circle和Point都有自己的名字——就是命名的类型名字——但是这些名字在点操作符中是可选的。我们在访问子成员的时候可以忽略任何匿名成员部分。
|
||||
|
||||
不幸的是,結構體字面值併沒有簡短表示匿名成員的語法, 因此下面的語句都不能編譯通過:
|
||||
不幸的是,结构体字面值并没有简短表示匿名成员的语法, 因此下面的语句都不能编译通过:
|
||||
|
||||
```Go
|
||||
w = Wheel{8, 8, 5, 20} // compile error: unknown fields
|
||||
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
|
||||
```
|
||||
|
||||
結構體字面值必須遵循形狀類型聲明時的結構,所以我們隻能用下面的兩種語法,它們彼此是等價的:
|
||||
结构体字面值必须遵循形状类型声明时的结构,所以我们只能用下面的两种语法,它们彼此是等价的:
|
||||
|
||||
<u><i>gopl.io/ch4/embed</i></u>
|
||||
```Go
|
||||
@@ -110,16 +110,16 @@ fmt.Printf("%#v\n", w)
|
||||
// Wheel{Circle:Circle{Point:Point{X:42, Y:8}, Radius:5}, Spokes:20}
|
||||
```
|
||||
|
||||
需要註意的是Printf函數中%v參數包含的#副詞,它表示用和Go語言類似的語法打印值。對於結構體類型來説,將包含每個成員的名字。
|
||||
需要注意的是Printf函数中%v参数包含的#副词,它表示用和Go语言类似的语法打印值。对于结构体类型来说,将包含每个成员的名字。
|
||||
|
||||
因爲匿名成員也有一個隱式的名字,因此不能同時包含兩個類型相同的匿名成員,這會導致名字衝突。同時,因爲成員的名字是由其類型隱式地決定的,所有匿名成員也有可見性的規則約束。在上面的例子中,Point和Circle匿名成員都是導出的。卽使它們不導出(比如改成小寫字母開頭的point和circle),我們依然可以用簡短形式訪問匿名成員嵌套的成員
|
||||
因为匿名成员也有一个隐式的名字,因此不能同时包含两个类型相同的匿名成员,这会导致名字冲突。同时,因为成员的名字是由其类型隐式地决定的,所有匿名成员也有可见性的规则约束。在上面的例子中,Point和Circle匿名成员都是导出的。即使它们不导出(比如改成小写字母开头的point和circle),我们依然可以用简短形式访问匿名成员嵌套的成员
|
||||
|
||||
```Go
|
||||
w.X = 8 // equivalent to w.circle.point.X = 8
|
||||
```
|
||||
|
||||
但是在包外部,因爲circle和point沒有導出不能訪問它們的成員,因此簡短的匿名成員訪問語法也是禁止的。
|
||||
但是在包外部,因为circle和point没有导出不能访问它们的成员,因此简短的匿名成员访问语法也是禁止的。
|
||||
|
||||
到目前爲止,我們看到匿名成員特性隻是對訪問嵌套成員的點運算符提供了簡短的語法糖。稍後,我們將會看到匿名成員併不要求是結構體類型;其實任何命名的類型都可以作爲結構體的匿名成員。但是爲什麽要嵌入一個沒有任何子成員類型的匿名成員類型呢?
|
||||
到目前为止,我们看到匿名成员特性只是对访问嵌套成员的点运算符提供了简短的语法糖。稍后,我们将会看到匿名成员并不要求是结构体类型;其实任何命名的类型都可以作为结构体的匿名成员。但是为什么要嵌入一个没有任何子成员类型的匿名成员类型呢?
|
||||
|
||||
答案是匿名類型的方法集。簡短的點運算符語法可以用於選擇匿名成員嵌套的成員,也可以用於訪問它們的方法。實際上,外層的結構體不僅僅是獲得了匿名成員類型的所有成員,而且也獲得了該類型導出的全部的方法。這個機製可以用於將一個有簡單行爲的對象組合成有複雜行爲的對象。組合是Go語言中面向對象編程的核心,我們將在6.3節中專門討論。
|
||||
答案是匿名类型的方法集。简短的点运算符语法可以用于选择匿名成员嵌套的成员,也可以用于访问它们的方法。实际上,外层的结构体不仅仅是获得了匿名成员类型的所有成员,而且也获得了该类型导出的全部的方法。这个机制可以用于将一个有简单行为的对象组合成有复杂行为的对象。组合是Go语言中面向对象编程的核心,我们将在6.3节中专门讨论。
|
||||
|
Reference in New Issue
Block a user