本文來自:CSDN博客golang
感謝做者:fengfengdiandia編程
查看原文:go 接口markdown
Go 語言不是一種 「傳統」 的面向對象編程語言:它裏面沒有類
和繼承
的概念。數據結構
可是 Go 語言裏有很是靈活的接口
概念,經過它能夠實現不少面向對象
的特性。編程語言
接口
定義了一個 方法的集合
,可是這些方法 不包含實現代碼
,它們是 抽象的
,接口裏也 不能包含變量
。測試
定義接口的通常格式:ui
type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... }
上面的 Namer
就是一個接口類型。spa
在 Go 語言中 接口
能夠有值, 一個 接口類型
的變量或一個 接口值
:var ai Namer
,ai
是一個 multiword
數據結構,它的值是 nil
。
它本質上是一個 指針
,雖然不徹底是一回事。指向接口值的指針是非法的
,會致使代碼錯誤。.net
類型
(好比結構體)實現接口方法集中的方法,實現了 Namer
接口類型的變量能夠賦值給 ai
,此時方法表中的指針會指向被實現的接口方法。3d
實現某個接口的類型,除了實現接口的方法外,還能夠有本身的方法。
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } type Rectangle struct { length float64 width float64 } // 實現 Shaper 接口中的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是屬於 Rectangle 本身的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } func main() { rect := new(Rectangle) rect.Set(2, 3) areaIntf := Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) }
若是去掉 Shaper
中 Perimeter() float64
的註釋,編譯的時候會遇到下面的錯誤,這是由於 Rectangle
沒有實現 Perimeter()
方法。
cannot convert rect (type *Rectangle) to type Shaper: *Rectangle does not implement Shaper (missing Perimeter method)
一、多個類型能夠實現同一個接口。
二、一個類型能夠實現多個接口。
下面咱們增長一個類型 Triangle
,一樣也爲它實現 Shaper
接口。
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } // ==== Rectangle ==== type Rectangle struct { length float64 width float64 } // 實現 Shaper 接口中的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是屬於 Rectangle 本身的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } // ==== Rectangle End ==== // ==== Triangle ==== type Triangle struct { bottom float64 hight float64 } func (t *Triangle) Area() float64 { return t.bottom * t.hight / 2 } func (t *Triangle) Set(b float64, h float64) { t.bottom = b t.hight = h } // ==== Triangle End ==== func main() { rect := new(Rectangle) rect.Set(2, 3) areaIntf := Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) triangle := new(Triangle) triangle.Set(2, 3) areaIntf = Shaper(triangle) fmt.Printf("The triangle has area: %f\n", areaIntf.Area()) }
接口的定義是比較靈活的。
假設接口和類型處於不一樣的包中,只要類型實現了接口中的所有方法,那麼它就實現了此接口。
如今咱們將 Shaper
的定義放在 shaper 包
下, Rectangle
和 Triangle
的定義放在 test 包
下:
[root@ src]# tree ├── test │ └── test.go ├── main.go └── shaper └── shaper.go
shaper.go
package shaper type Shaper interface { Area() float64 }
test.go
package test // ==== Rectangle ==== type Rectangle struct { length float64 width float64 } // 實現 Shaper 接口的方法 func (r *Rectangle) Area() float64 { return r.length * r.width } // Set 是屬於 Rectangle 本身的方法 func (r *Rectangle) Set(l float64, w float64) { r.length = l r.width = w } // ==== Rectangle End ==== // ==== Triangle ==== type Triangle struct { bottom float64 hight float64 } func (t *Triangle) Area() float64 { return t.bottom * t.hight / 2 } func (t *Triangle) Set(b float64, h float64) { t.bottom = b t.hight = h } // ==== Triangle End ==== // main.go package main import ( "fmt" "shaper" "test" ) func main() { rect := new(test.Rectangle) rect.Set(2, 3) areaIntf := shaper.Shaper(rect) fmt.Printf("The rect has area: %f\n", areaIntf.Area()) triangle := new(test.Triangle) triangle.Set(2, 3) areaIntf = shaper.Shaper(triangle) fmt.Printf("The triangle has area: %f\n", areaIntf.Area()) }
如今運行 main.go
看看結果吧,嗯嗯,沒什麼問題,^_^
The rect has area: 6.000000 The triangle has area: 3.000000
一個接口能夠包含一個或多個其餘的接口,這至關於直接將這些內嵌接口的方法列舉在外層接口中同樣。
好比接口 File
包含了 ReadWrite
和 Lock
的全部方法,它還額外有一個 Close()
方法。
type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type Lock interface { Lock() Unlock() } type File interface { ReadWrite Lock Close() }
假如我如今寫了一個結構體類型 MyFile
來實現上面的 File
接口,那麼我如何知道 MyFile
是否實現了 File
接口呢?
一般咱們使用 類型斷言
來測試在某個時刻 varI
是否包含類型 T
的值:
if v, ok : = varI.(T) ; ok { // checked type assertion Process(v) return } // varI is not of type T
若是 v
是 varI
轉換到類型 T
的值,ok
會是 true
;不然 v
是類型 T
的零值,ok
是 false
。
// main.go
package main import "fmt" type MyFile struct{} func (m *MyFile) Read() bool { fmt.Printf("Read()\n") return true } // ... // 假設我這裏相繼實現了 Write(), Lock(),Unlock() 和 Close() 方法 func main() { my := new(MyFile) fIntf := File(my) // 看這裏,看這裏 if v, ok := fIntf.(*MyFile); ok { v.Read() } }
輸出結果是:Read()
要是多個類型實現了同一個接口,好比前面的 areaIntf
,要如何測試呢?
那就要用 type-switch
來判斷了。
switch t := areaIntf.(type) { case *Rectangle: // do something case *Triangle: // do something default: // do something }