本文来自: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 }