package main import "fmt" type Shaper interface { Area() float32 } type Square struct { side float32 } func (sq *Square) Area() float32 { return sq.side * sq.side } func main() { sq1 := new(Square) sq1.side = 5 var areaIntf Shaper areaIntf = sq1 // shorter,without separate declaration: // areaIntf := Shaper(sq1) // or even: // areaIntf := sq1 fmt.Printf("The square has area: %f\n", areaIntf.Area()) }
上面的程序定義了一個結構體 Square
和一個接口 Shaper
,接口有一個方法 Area()
。編程
在 main()
方法中建立了一個 Square
的實例。在主程序外邊定義了一個接收者類型是 Square
方法的 Area()
,用來計算正方形的面積:結構體 Square
實現了接口 Shaper
。數組
因此能夠將一個 Square
類型的變量賦值給一個接口類型的變量:areaIntf = sq1
。ide
如今接口變量包含一個指向 Square
變量的引用,經過它能夠調用 Square
上的方法 Area()
。固然也能夠直接在 Square
的實例上調用此方法,可是在接口實例上調用此方法更使人興奮,它使此方法更具備通常性。接口變量裏包含了接收者實例的值和指向對應方法表的指針。oop
這是 多態 的 Go 版本,多態是面向對象編程中一個廣爲人知的概念:根據當前的類型選擇正確的方法,或者說:同一種類型在不一樣的實例上彷佛表現出不一樣的行爲。this
若是 Square
沒有實現 Area()
方法,編譯器將會給出清晰的錯誤信息:lua
cannot use sq1 (type *Square) as type Shaper in assignment: *Square does not implement Shaper (missing Area method)
若是 Shaper
有另一個方法 Perimeter()
,可是Square
沒有實現它,即便沒有人在 Square
實例上調用這個方法,編譯器也會給出上面一樣的錯誤。spa
擴展一下上面的例子,類型 Rectangle
也實現了 Shaper
接口。接着建立一個 Shaper
類型的數組,迭代它的每個元素並在上面調用 Area()
方法,以此來展現多態行爲:指針
package main import "fmt" type Shaper interface { Area() float32 } type Square struct { side float32 } func (sq *Square) Area() float32 { return sq.side * sq.side } type Rectangle struct { length, width float32 } func (r Rectangle) Area() float32 { return r.length * r.width } func main() { r := Rectangle{5, 3} // Area() of Rectangle needs a value q := &Square{5} // Area() of Square needs a pointer // shapes := []Shaper{Shaper(r), Shaper(q)} // or shorter shapes := []Shaper{r, q} fmt.Println("Looping through shapes for area ...") for n, _ := range shapes { fmt.Println("Shape details: ", shapes[n]) fmt.Println("Area of this shape is: ", shapes[n].Area()) } }
在調用 shapes[n].Area()
這個時,只知道 shapes[n]
是一個 Shaper
對象,最後它搖身一變成爲了一個 Square
或 Rectangle
對象,而且表現出了相對應的行爲。code
在調用 shapes[n].Area()
這個時,只知道 shapes[n]
是一個 Shaper
對象,最後它搖身一變成爲了一個 Square
或 Rectangle
對象,而且表現出了相對應的行爲。對象
package main import "fmt" type stockPosition struct { ticker string sharePrice float32 count float32 } /* method to determine the value of a stock position */ func (s stockPosition) getValue() float32 { return s.sharePrice * s.count } type car struct { make string model string price float32 } /* method to determine the value of a car */ func (c car) getValue() float32 { return c.price } /* contract that defines different things that have value */ type valuable interface { getValue() float32 } func showValue(asset valuable) { fmt.Printf("Value of the asset is %f\n", asset.getValue()) } func main() { var o valuable = stockPosition{"GOOG", 577.20, 4} showValue(o) o = car{"BMW", "M3", 66500} showValue(o) }
數據類型實現了接口,就能使用以接口變量爲參數的方法
備註:
有的時候,也會以一種稍微不一樣的方式來使用接口這個詞:從某個類型的角度來看,它的接口指的是:它的全部導出方法,只不過沒有顯式地爲這些導出方法額外定一個接口而已。