簡單的介面

在 Go 中,介面只是一組方法。我們使用介面來指定給定物件的行為。

type Painter interface {
    Paint()
}

實現型別不需要宣告它正在實現介面。定義相同簽名的方法就足夠了。

type Rembrandt struct{}

func (r Rembrandt) Paint() {
    // use a lot of canvas here 
}

現在我們可以將結構用作介面。

var p Painter
p = Rembrandt{}

可以通過任意數量的型別來滿足(或實現)介面。型別也可以實現任意數量的介面。

type Singer interface {
     Sing()
}

type Writer interface {
     Write()
}

type Human struct{}

func (h *Human) Sing() {
    fmt.Println("singing")
}

func (h *Human) Write() {
    fmt.Println("writing")
}

type OnlySinger struct{}
func (o *OnlySinger) Sing() {
    fmt.Println("singing")
}

這裡,Human 結構同時滿足 SingerWriter 介面,但 OnlySinger 結構只滿足 Singer 介面。

空介面

有一個空的介面型別,它不包含任何方法。我們宣告它為 interface{}。這不包含任何方法,因此每個 type 都滿足它。因此,空介面可以包含任何型別值。

var a interface{}
var i int = 5
s := "Hello world"

type StructType struct {
    i, j int
    k string
}

// all are valid statements
a = i
a = s
a = &StructType{1, 2, "hello"}

介面最常見的用例是確保變數支援一個或多個行為。相比之下,空介面的主要用例是定義一個可以儲存任何值的變數,而不管其具體型別如何。

要將這些值恢復為原始型別,我們只需要這樣做

i = a.(int)
s = a.(string)
m := a.(*StructType)

要麼

i, ok := a.(int)
s, ok := a.(string)
m, ok := a.(*StructType)

ok 表示 interface a 是否可轉換為給定型別。如果不可能施展 ok 將是 false

介面值

如果宣告介面的變數,它可以儲存實現介面宣告的方法的任何值型別!

如果我們宣告 interface Singerh,它可以儲存 HumanOnlySinger. 型別的值。這是因為它們都實現了 Singer 介面指定的方法。

var h Singer
h = &human{}

h.Sing()