這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在 Go 中,類型可以定義接收此類型的函數,即方法。每個類型都有介面,意味著對那個類型定義了方法集合。
下面定義了結構體類型 S 以及它的兩個方法:
type S struct { i int }func (p *S) Get() int { return p.i }func (p *S) Put(v int) { p.i = v }
方法
方法就是有接收者的函數。
可以在除了非本地類型(包括內建類型,比如 int)的任意類型上定義方法。然而可以為內建類型定義別名,然後就可以為別名定義方法。如
type Foo int // 為 int 定義別名 Foofunc (self Foo) Emit() { fmt.Printf("%v", self)}
介面
介面定義為一個方法的集合。方法包含實際的代碼。換句話說,一個介面就是定義,而方法就是實現。因此,接收者不能定義為介面類型,這樣做的話會引起 invalid receiver type … 的編譯器錯誤。
來自語言說明書的權威內容:
接收者類型必須是T 或*T,這裡的 T 是類型名。 T 叫做接收者基礎類型或簡稱基礎類型。基礎類型一定不能是指標或介面類型,並且定義在與方法相同的包中。
// 定義了有兩個方法的介面 I,結構 S 實現了此介面type I interface { Get() int Put( int)}
可以定義介面類型的變數(介面值)作為函數的參數,實現了此介面的類型的變數可以作為實參傳遞給該介面變數並調用其方法。
func f(p I) { fmt.Println(p.Get()) p.Put(1)}var s Sf(&s) // S 類型的變數 s 作為實參傳給介面。取地址是因為在 s 的指標上定義了方法,這樣可以修改 s; // 如果在 s 上定義方法,則修改的只是 s 的副本
在 Go 中建立指向介面的指標是無意義的。建立介面值的指標也是非法的。
介面類型判斷
在 Go 中,要判斷傳遞給介面值的變數類型,可以在使用 type switch 得到。(type)只能在 switch 中使用。
// 另一個實現了 I 介面的 R 類型type R struct { i int }func (p *R) Get() int { return p.i }func (p *R) Put(v int) { p.i = v }func f(p I) { switch t := p.(type) { // 判斷傳遞給 p 的實際類型 case *S: // 指向 S 的指標類型 case *R: // 指向 R 的指標類型 case S: // S 類型 case R: // R 類型 default: //實現了 I 介面的其他類型 }}
若要在 switch 外判斷一個介面類型是否實現了某個介面,可以使用“逗號 ok ”。
value, ok := Interfacevariable.(implementType)
其中 Interfacevariable 是介面變數(介面值),implementType 為實現此介面的類型,value 返回介面變數實際類型變數的值,如果該類型實現了此介面返回 true。
type I interface{ // 有一個方法的介面 I Get() Int}type Int int // Int 類型實現了 I 介面func (i Int) Get() Int{ return i}var myint Int = 5var inter I = myint // 變數賦值給介面val, ok := inter.(Int)fmt.Printf("%v, %v", val, ok) // 輸出為:5,true
空介面
每種類型都能匹配到空介面:interface{}。空介面類型對方法沒有任何約束(因為沒有方法),它能包含任意類型,也可以實現到其他介面類型的轉換。如果傳遞給該介面的類型變數實現了轉換後的介面則可以正常運行,否則出現執行階段錯誤。
func g(si interface{}) int { return si.(I).Get()}s = new(S)g(s) // (I) 將 si 轉換到 I 類型的介面,s 實現了 Get 方法,因此可以調用 g()i := 5g(i) // 運行時出錯,因為 int 型沒有 Get 方法
還可以在介面中列出另一個介面,如
type Interface interface { sort.Interface // 另一個介面 Push(x interface{}) Pop() interface{}}
自省和反射
…
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。