這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。1)哪些類型可以有方法:
1)只能對命名類型和命名類型的指標編寫方法;
2)不能對介面類型和介面類型的指標編寫方法;
3)只能在定義命名類型的那個包編寫其方法。
2)receiver是值的方法,編譯器會隱式的產生一個receiver是對應類型指標的同名方法。反過來卻不會。
3)結構體的匿名欄位的類型限制:
1)不可以是未命名類型;
2)可以是命名類型或命令類型的指標類型;
3)介面類型可以,介面類型的指標類型不行;
4)結構體匿名欄位的方法向外傳遞的規則:
1)匿名欄位為實值型別時:值的方法會傳遞給結構體的值,指標的方法會傳遞給結構體的指標;
2)匿名欄位為指標類型時:指標的方法會傳遞給值和指標;
3)匿名欄位為介面類型時:方法會傳遞給值和指標;
5)匿名欄位的方法,是被經過封裝實現為外圍結構體的方法。
6)使用具體的類型去調用方法時。
首先,編譯器查看該類型下有沒有該方法;
其次,擴充查看該類型的指標類型或者基底類型(如果該類型是指標類型);
最後,如果以上尋找都未找到,則會報錯。
註:擴充查看不會查看隱式實現的方法(匿名欄位傳遞出來的方法、值=>指標隱式實現的方法)
7)具體類型的方法集是以該類型為receiver的方法的集合。
8)介面類型的方法集就是其定義裡聲明的方法,介面調用方法時類似C++調用虛函數;介面的指標沒有方法集。
9)類型存入介面時只檢查方法集;調用介面的方法時也只檢查方法集;reflect包同樣只查看方法集。
因此:
類型A的方法,A和*A都可以調用;
類型A的方法,雖然隱式實現了類型*A的方法,**A卻不能調用;
類型*A的方法,A、*A、**A都可以調用;
不能實現**A的方法;
type A ...func (a A)X(){}func (a *A)Y(){}type IX interface{X()}type IY interface{Y()}a := A{}b := &ac := &ba.X() // okb.X() // okc.X() // errora.Y() // okb.Y() // okc.Y() // okvar ix IXix = a // okix = b // okix = c // errorvar iy IYiy = a // erroriy = b // okiy = c // errorvar jx IXjx = ix // okjx = &ix // error
對於代碼:
type I interface {IE()}type A intfunc (_ A) VA() {}func (_ *A) PA() {}type B struct {I}func (_ B) VB() {}func (_ *B) PB() {}type C struct {A}func (_ C) VC() {}func (_ *C) PC() {}type D struct {*A}func (_ D) VD() {}func (_ *D) PD() {}
下面的列表說明了其方法集和方法的來源:
type(類型) |
explicit(顯式定義的方法) |
implicit(隱式實現的方法) |
inherit(繼承自匿名欄位的方法) |
I |
IE |
|
|
*I |
|
|
|
A |
VA |
|
|
*A |
PA |
VA |
|
B |
VB |
|
IE |
*B |
PB |
VB |
IE |
C |
VC |
|
VA |
*C |
PC |
VC |
PA,VA |
D |
VD |
|
PA,VA |
*D |
PD |
VD |
PA,VA |