This commit is contained in:
chai2010
2016-01-02 21:17:21 +08:00
parent 8772a9c000
commit ba03c527c0
17 changed files with 63 additions and 29 deletions

View File

@@ -44,6 +44,7 @@ fmt.Println(p) // "{2, 4}"
```
不過後面兩種方法有些笨拙。幸運的是go語言本身在這種地方會幫到我們。如果接收器p是一個Point類型的變量併且其方法需要一個Point指針作爲接收器我們可以用下面這種簡短的寫法
```go
p.ScaleBy(2)
```
@@ -61,21 +62,23 @@ pptr.Distance(q)
(*pptr).Distance(q)
```
Lets summarize these three cases again, since they are a frequent point of confusion. In every valid method call expression, exactly one of these three statements is true.
這里的幾個例子可能讓你有些睏惑,所以我們總結一下:在每一個合法的方法調用表達式中,也就是下面三種情況里的任意一種情況都是可以的:
不論是接收器的實際參數和其接收器的形式參數相同比如兩者都是類型T或者都是類型`*T`
```go
Point{1, 2}.Distance(q) // Point
pptr.ScaleBy(2) // *Point
```
或者接收器形參是類型T但接收器實參是類型`*T`,這種情況下編譯器會隱式地爲我們取變量的地址:
```go
p.ScaleBy(2) // implicit (&p)
```
或者接收器形參是類型`*T`實參是類型T。編譯器會隱式地爲我們解引用取到指針指向的實際變量
```go
pptr.Distance(q) // implicit (*pptr)
```
@@ -83,6 +86,7 @@ pptr.Distance(q) // implicit (*pptr)
如果類型T的所有方法都是用T類型自己來做接收器(而不是`*T`)那麽拷貝這種類型的實例就是安全的調用他的任何一個方法也就會産生一個值的拷貝。比如time.Duration的這個類型在調用其方法時就會被全部拷貝一份包括在作爲參數傳入函數的時候。但是如果一個方法使用指針作爲接收器你需要避免對其進行拷貝因爲這樣可能會破壞掉該類型內部的不變性。比如你對bytes.Buffer對象進行了拷貝那麽可能會引起原始對象和拷貝對象隻是别名而已但實際上其指向的對象是一致的。緊接着對拷貝後的變量進行脩改可能會有讓你意外的結果。
譯註:作者這里説的比較繞,其實有兩點:
1.不管你的method的receiver是指針類型還是非指針類型都是可以通過指針/非指針類型進行調用的,編譯器會幫你做類型轉換
2.在聲明一個method的receiver該是指針還是非指針類型時你需要考慮兩方面的內部第一方面是這個對象本身是不是特别大如果聲明爲非指針變量時調用會産生一次拷貝第二方面是如果你用指針類型作爲receiver那麽你一定要註意這種指針類型指向的始終是一塊內存地址就算你對其進行了拷貝。熟悉C或者C艹的人這里應該很快能明白。
@@ -109,7 +113,6 @@ func (list *IntList) Sum() int {
下面是net/url包里Values類型定義的一部分。
```go
net/url
package url