interface作为struct field,谈谈golang结构体中的匿名接口
golang中通过组合(composite)实现类似继承(extends)和重写(override)的功能,大家可能平时用的比较多的是struct中匿名struct的写法,有没有见过struct中匿名接口(anonymous interface)的写法呢?
Interface这个接口直接作为struct中的一个匿名字段,在标准库sort包中就有这种写法:
type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) } type reverse struct { Interface }
下面我们来看一个完整的例子,以下代码是从sort包提取出来的:
package main import ( "fmt" ) type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) } // Array 实现Interface接口 type Array []int func (arr Array) Len() int { return len(arr) } func (arr Array) Less(i, j int) bool { return arr[i] < arr[j] } func (arr Array) Swap(i, j int) { arr[i], arr[j] = arr[j], arr[i] } // 匿名接口(anonymous interface) type reverse struct { Interface } // 重写(override) func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) } // 构造reverse Interface func Reverse(data Interface) Interface { return &reverse{data} } func main() { arr := Array{1, 2, 3} rarr := Reverse(arr) fmt.Println(arr.Less(0,1)) fmt.Println(rarr.Less(0,1)) }
sort包中这么写的目的是为了重写Interface的Less方法,并有效利用了原始的Less方法;通过Reverse可以从Interface构造出一个反向的Interface。go语言利用组合的特性,寥寥几行代码就实现了重写。
对比一下传统的组合匿名结构体实现重写的写法,或许可以更好的帮助我们了解匿名接口的优点:
package main import ( "fmt" ) type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) } type Array []int func (arr Array) Len() int { return len(arr) } func (arr Array) Less(i, j int) bool { return arr[i] < arr[j] } func (arr Array) Swap(i, j int) { arr[i], arr[j] = arr[j], arr[i] } // 匿名struct type reverse struct { Array } // 重写 func (r reverse) Less(i, j int) bool { return r.Array.Less(j, i) } // 构造reverse Interface func Reverse(data Array) Interface { return &reverse{data} } func main() { arr := Array{1, 2, 3} rarr := Reverse(arr) fmt.Println(arr.Less(0, 1)) fmt.Println(rarr.Less(0, 1)) }
上面这个例子使用了匿名结构体的写法,和之前匿名接口的写法实现了同样的重写功能,甚至非常相似。但是仔细对比一下你就会发现匿名接口的优点,匿名接口的方式不依赖具体实现,可以对任意实现了该接口的类型进行重写。这在写一些公共库时会非常有用,如果你经常看一些库的源码,匿名接口的写法应该会很眼熟。
匿名接口还有一个作用就是对结构体添加一些约束,必须使用实现了该接口的类型来构造实例。结构体中可以包含一些其他的字段,而interface只有方法,没有field。
package main import ( "fmt" "reflect" "sort" ) type Array1 []int func (arr Array1) Len() int { return len(arr) } func (arr Array1) Less(i, j int) bool { return arr[i] < arr[j] } func (arr Array1) Swap(i, j int) { arr[i], arr[j] = arr[j], arr[i] } type Array2 []int func (arr Array2) Len() int { return len(arr) } func (arr Array2) Less(i, j int) bool { return arr[i] < arr[j] } func (arr Array2) Swap(i, j int) { arr[i], arr[j] = arr[j], arr[i] } type Sortable struct { sort.Interface // other field Type string } func NewSortable(i sort.Interface) Sortable { t := reflect.TypeOf(i).String() return Sortable{ Interface: i, Type: t, } } func DoSomething(s Sortable) { fmt.Println(s.Type) fmt.Println(s.Len()) fmt.Println(s.Less(0, 1)) } func main() { arr1 := Array1{1, 2, 3} arr2 := Array2{3, 2, 1, 0} DoSomething(NewSortable(arr1)) DoSomething(NewSortable(arr2)) }
相关推荐
yanyongtao 2020-11-02
shawsun 2020-07-04
us0 2020-06-28
cxcxrs 2020-06-26
小海 2020-06-25
Skyline 2020-06-16
jiedinghui 2020-06-04
数据与算法之美 2020-05-27
breakpoints 2020-05-17
cuterabbitbaby 2020-05-14
吴小伟 2020-05-09
程序员之怒 2020-04-26
doupoo 2020-05-04
Ghero 2020-05-03
chibangyuxun 2020-04-30
ThinkingLink 2020-04-26