This article comes from: CSDN blog
Thanks Author: fengfengdiandia
See original: Go Interface
Go Language is not a "traditional" object-oriented programming language: it is not inside 类
and 继承
concepts.
But the Go language has a very flexible 接口
concept, we can achieve a lot through its 面向对象
features.
接口
It defines a 方法的集合
, but these methods 不包含实现代码
, they are 抽象的
, there is also the interface 不能包含变量
.
Definition Format
The general format definition of the interface:
type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... }
The above Namer
is an interface type.
However, in Go 接口
may have a value, a 接口类型
variable or a 接口值
: var ai Namer
, ai
it is a multiword
data structure, its value is nil
.
It's essentially a 指针
, though not exactly the same thing. Value is a pointer to the interface 非法的
will result in coding errors.
类型
(Such as structure) implemented method interface method set achieved Namer
interface types can be assigned to a variable ai
, then the method table pointer points to the interface methods are implemented.
Implementation type of an interface, in addition to the implementation of the interface method, you can also have their own methods.
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } type Rectangle struct { length float64 width float64 } // Implementation Shaper interface func (r *Rectangle) Area() float64 { return r.length * r.width } // Set belongs Rectangle own way 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()) }
If you remove Shaper
the Perimeter() float64
comments, you will encounter the following compile time error, because Rectangle
not implemented Perimeter()
method.
cannot convert rect (type *Rectangle) to type Shaper: *Rectangle does not implement Shaper (missing Perimeter method)
Polymorphism
1, a plurality of types can implement the same interface.
2, a plurality of types of interfaces may be achieved.
Here we add a type Triangle
, it is also implemented as Shaper
an interface.
package main import "fmt" type Shaper interface { Area() float64 // Perimeter() float64 } // ==== Rectangle ==== type Rectangle struct { length float64 width float64 } // Implementation Shaper interface func (r *Rectangle) Area() float64 { return r.length * r.width } // Set belongs Rectangle own way 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()) }
flexibility
Definition of the interface is more flexible.
Suppose in different types of interfaces, and packages, as long as the type implements all the methods in an interface, then it implements this interface.
Now we will Shaper
define in shaper 包
the next, Rectangle
and Triangle
the definition on the test 包
next:
[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 } // interface method to achieve Shaper func (r *Rectangle) Area() float64 { return r.length * r.width } // Set belongs Rectangle own way 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()) }
Now run main.go
to see the results of it, uh-huh, no problem, ^ _ ^
The rect has area: 6.000000
The triangle has area: 3.000000
Nesting Interface
An interface may comprise one or more other interfaces, which corresponds directly to the interfaces of these methods embedded in the outer layer include the same interface.
For example, the interface File
includes ReadWrite
and Lock
all methods, it also has an additional Close()
method.
type ReadWrite interface { Read(b Buffer) bool Write(b Buffer) bool } type Lock interface { Lock() Unlock() } type File interface { ReadWrite Lock Close() }
Type assertion
If I wrote a structure type MyFile
to achieve the above File
interface, how do I know MyFile
whether to implement the File
interface to it?
Usually we use 类型断言
to test at some point varI
whether to include types of T
values:
if v, ok : = varI.(T) ; ok { // checked type assertion Process(v) return } // varI is not of type T
If you v
are varI
converting to the type of T
value ok
will be true
; otherwise it v
is the type of T
zero value, ok
is false
.
// main.go
package main import "fmt" type MyFile struct{} func (m *MyFile) Read() bool { fmt.Printf("Read()\n") return true } // ... // Let's say I have achieved here Write (), Lock (), Unlock () and Close () method func main() { my := new(MyFile) fIntf := File(my) // look here, look here if v, ok := fIntf.(*MyFile); ok { v.Read() } }
The output is: Read ()
If more than one type implements the same interface, such as front areaIntf
, how to test it?
Then use type-switch
to judge.
type-switch type judgment
switch t := areaIntf.(type) { case *Rectangle: // do something case *Triangle: // do something default: // do something }