接口
接口类型是由一组方法定义的集合。
package main
import (
"math"
"fmt"
)
type Abser interface {
Abs() float64
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f<0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
fmt.Println(v.Abs())
a = f
a = &v
// 下面一行,v 是一个 Vertex(而不是 *Vertex)
// 所以没有实现 Abser。
//a = v
fmt.Println(a.Abs())
}
接受者和方法集:
方法集 | 接受者 |
---|---|
(t T) | T 和 *T |
(t *T) | *T |
但是这里我们注意到,下面的方法执行是不会抛出上面的错误的,这是因为 值方法和指针方法遵循如下规则:
- 接受者变量代表的值是源值的复制品。如果这个值不是指针类型,那么在值方法中就没有途径改变源值。而指针与其复制指向的则是同一个值。
- 对于某个非指针的数据类型,与它关联的方法集只包含它的值方法。而对于它的指针类型,其方法集包含值方法和指针方法。在非指针数据类型上也能调用其指针方法,因为GO在内部会做自动转换,如:add是一个指针方法,t.add(2) -> (&t).add(2),这也是为什么下面第一条成功执行,第二条失败的原因。
fmt.Println(v.Abs())
VS
a = v // 因为这里进行了值复制,&a 和 &v 会不同
fmt.Println(a.Abs())
Go 的数据结构之间并不存在继承关系,接口类型之间也是如此