接口(interface) 反射 (reflection)
// 定义了接口
type Shaper interface {
// 接口中定义方法和他的返回值
// 并不包含代码块
Area() float32
// Perimeter() float32
}
type Square struct {
side float32
}
// Square实现了接口的Area()方法
func (sq *Square) Area() float32 {
return sq.side * sq.side
}
type Rectangel struct {
w, h float32
}
// Rectangle实现了接口的Area()方法
func (rec *Rectangel) Area() float32{
return rec.h * rec.w
}
接口是Go实现多态的版本。如果类型没有实现接口的全部方法就会出现编译错误,给Shaper添加方法Perimeter()
,编译则会提示错误*Square does not implement Shaper (missing Perimeter method)
。
接口嵌套接口
type ReadWrite interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type Lock interface {
Lock()
Unlock()
}
type File interface {
ReadWrite
Lock
Close()
}
类型断言:检测和转换接口变量类型
判断接口中是否存在类型
type Square struct {
side float32
}
type Circle struct {
radius float32
}
type Shaper interface {
Area() float32
}
// 省略了部分代码
var ateaIntf Shaper
sq1 := &Square{5}
areaIntf = sq1
if t, ok := areaIntf.(*Square); ok {}// ok : true
if t, ok := areaIntf.(*Circle); ok {}// ok : false
其中*
必须要有,不然会编译出错
类型判断:tyoe-switch
switch t := areaIntf.(type) {
case *Square:
fmt.Printf("Type Square %T with value %v\n", t, t)
case *Circle:
fmt.Printf("Type Circle %T with value %v\n", t, t)
case nil:
fmt.Printf("nil value: nothing to check?\n")
default:
fmt.Printf("Unexpected type %T\n", t)
}
测试一个值是否实现了某个接口
type Stringer interface {
String() string
}
if sv, ok := v.(Stringer); ok {
fmt.Printf("v implements String(): %s\n", sv.String()) // note: sv, not v
}
判断v是否实现了String接口
方法集与接口
作用于变量上的方法实际上是不区分变量到底是指针还是值的。
Go 语言规范定义了接口方法集的调用规则:
- 类型 T 的可调用方法集包含接受者为 *T 或 T 的所有方法集
- 类型 *T 的可调用方法集包含接受者为 *T 的所有方法
- 类型 *T 的可调用方法集不包含接受者为 T 的方法
空接口
或称为**最小接口 **不包含任何方法,它对实现不做任何要求:
type Any interface {}
类似Java中的所有类的基类:Object
每个interface {}
变量在内存中占据两个字长:一个存类型,一个存数据或是指向数据的指针。
可以利用空接口实现通用类型。
type Node struct {
le *Node
data interface{}
ri *Node
}
func NewNode(le, ri *Node) *Node {
return &Node{le, nil, ri}
}
func(n *Node) SetData(data interface{}) {
n.data = data
}
func main() {
root := NewNode(nil, nil)
root.SetData("Root")
a := NewNode(nil, nil)
b := NewNode(nil, nil)
root.le = a
root.ri = b
fmt.Print(root)
}
反射包
反射是用程序检查其所拥有的结构。
提取接口
使得整个设计可以持续演进,类要实现某个接口,只需要在这个类上实现新的方法。
总结
我们总结一下前面看到的:Go 没有类,而是松耦合的类型、方法对接口的实现。
- 封装通过可见性实现
- 继承通过组合
- 多态通过接口实现