天天看點

Go 方法、接口

在 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 定義别名 Foo
func (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)
}

var s S
f(&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 =
var 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 :=
g(i) // 運作時出錯,因為 int 型沒有 Get 方法
           

還可以在接口中列出另一個接口,如

type Interface interface {
    sort.Interface // 另一個接口
    Push(x interface{})
    Pop() interface{}
}
           
自省和反射