多态(polymorphism)
多态是接口的一个关键功能和Go语言的一个重要特性。
当非接口类型T的一个值t被包裹在接口类型I的一个接口值i中,通过i调用接口类型I指定的一个方法时,事实上为非接口类型T声明的对应方法将通过非接口值t被调用。 换句话说,调用一个接口值的方法实际上将调用此接口值的动态值的对应方法。 比如,当方法i.m被调用时,其实被调用的是方法t.m。 一个接口值可以通过包裹不同动态类型的动态值来表现出各种不同的行为,这称为多态。
当方法i.m被调用时,i存储的实现关系信息的方法表中的方法t.m将被找到并被调用。 此方法表是一个切片,所以此寻找过程只不过是一个切片元素访问操作,不会消耗很多时间。
注意,在nil接口值上调用方法将产生一个恐慌,因为没有具体的方法可被调用。
一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package main
import "fmt"
type Filter interface { About() string Process([]int) []int }
type UniqueFilter struct{} func (UniqueFilter) About() string { return "删除重复的数字" } func (UniqueFilter) Process(inputs []int) []int { outs := make([]int, 0, len(inputs)) pusheds := make(map[int]bool) for _, n := range inputs { if !pusheds[n] { pusheds[n] = true outs = append(outs, n) } } return outs }
type MultipleFilter int func (mf MultipleFilter) About() string { return fmt.Sprintf("保留%v的倍数", mf) } func (mf MultipleFilter) Process(inputs []int) []int { var outs = make([]int, 0, len(inputs)) for _, n := range inputs { if n % int(mf) == 0 { outs = append(outs, n) } } return outs }
func filteAndPrint(fltr Filter, unfiltered []int) []int { filtered := fltr.Process(unfiltered) fmt.Println(fltr.About() + ":\n\t", filtered) return filtered }
func main() { numbers := []int{12, 7, 21, 12, 12, 26, 25, 21, 30} fmt.Println("过滤之前:\n\t", numbers)
filters := []Filter{ UniqueFilter{}, MultipleFilter(2), MultipleFilter(3), }
for _, fltr := range filters { numbers = filteAndPrint(fltr, numbers) } }
|
输出结果:
1 2 3 4 5 6 7 8
| 过滤之前: [12 7 21 12 12 26 25 21 30] 删除重复的数字: [12 7 21 26 25 30] 保留2的倍数: [12 26 30] 保留3的倍数: [12 30]
|
在上面这个例子中,多态使得我们不必为每个过滤器类型写一个单独的filteAndPrint函数。
除了上述这个好处,多态也使得一个代码包的开发者可以在此代码包中声明一个接口类型并声明一个拥有此接口类型参数的函数(或者方法),从而此代码包的一个用户可以在用户包中声明一个实现了此接口类型的用户类型,并且将此用户类型的值做为实参传递给此代码包中声明的函数(或者方法)的调用。 此代码包的开发者并不用关心一个用户类型具体是如何声明的,只要此用户类型满足此代码包中声明的接口类型规定的行为即可。
事实上,多态对于一个语言来说并非一个不可或缺的特性。我们可以通过其它途径来实现多态的作用。 但是,多态可以使得我们的代码更加简洁和优雅。