1.Go的动态类型
接收一个(或多个)接口类型作为参数的函数,其实参可以是任何实现了该接口的类型。 实现了某个接口的类型可以被传给任何以此接口为参数的函数
动态类型(duck typing)
package mainimport "fmt"type IDuck interface {Quack()Walk()}func DuckDance(duck IDuck) {for i := 1; i <= 3; i++ {duck.Quack()duck.Walk()}}type Bird struct {}func (b *Bird) Quack() {fmt.Println("I am quacking!")}func (b *Bird) Walk() {fmt.Println("i am walking")}func main() {b := &Bird{}DuckDance(b)}
2.动态方法调用
如果方法调用作用于像 interface{} 这样的“泛型”上,你可以通过类型断言(参见 11.3 节)来检查变量是否实现了相应接口。
//例如,你用不同的类型表示 XML 输出流中的不同实体。//然后我们为 XML 定义一个如下的“写”接口(甚至可以把它定义为私有接口):type xmlWriter interface {WriteXML(w io.Writer) error}//现在我们可以实现适用于该流类型的任何变量的 StreamXML 函数,//并用类型断言检查传入的变量是否实现了该接口;//如果没有,我们就调用内建的 encodeToXML 来完成相应工作:// Exported XML streaming function.func StreamXML(v interface{}, w io.Writer) error {if xw, ok := v.(xmlWriter); ok {// It’s an xmlWriter, use method of asserted type.return xw.WriteXML(w)}// No implementation, so we have to use our own function (with perhaps reflection):return encodeToXML(v, w)}// Internal XML encoding function.func encodeToXML(v interface{}, w io.Writer) error {// ...}
3.接口的提取
提取接口 是非常有用的设计模式,可以减少需要的类型和方法数量,而且不需要像传统的基于类的面向对象语言那样维护整个的类层次结构。
所以你不用提前设计出所有的接口;整个设计可以持续演进,而不用废弃之前的决定。类型要实现某个接口,它本身不用改变,你只需要在这个类型上实现新的方法。
4.显式地指明类型实现了某个接口
如果你希望满足某个接口的类型显式地声明它们实现了这个接口,你可以向接口的方法集中添加一个具有描述性名字的方法。例如:
type Fooer interface {Foo()ImplementsFooer()}
类型 Bar 必须实现 ImplementsFooer 方法来满足 Footer 接口,以清楚地记录这个事实。
type Bar struct{}func (b Bar) ImplementsFooer() {}func (b Bar) Foo() {}
5.空接口和函数重载
在 Go 语言中函数重载可以用可变参数 …T 作为函数最后一个参数来实现(参见 6.3 节)。如果我们把 T 换为空接口,那么可以知道任何类型的变量都是满足 T (空接口)类型的,这样就允许我们传递任何数量任何类型的参数给函数,即重载的实际含义
6.接口的继承
当一个类型包含(内嵌)另一个类型(实现了一个或多个接口)的指针时,这个类型就可以使用(另一个类型)所有的接口方法。
例如:
type Task struct {Command string*log.Logger}//当 log.Logger 实现了 Log() 方法后,Task 的实例 task 就可以调用该方法:task.Log()
类型可以通过继承多个接口来提供像 多重继承 一样的特性
type ReaderWriter struct {*io.Reader*io.Writer}
示例
package mainimport "fmt"type Any interface {}type Car struct {Model stringManufacturer stringBuildYear int}type Cars []*Car//用给定函数f处理所有汽车func (cs Cars) Process(f func(car *Car)) {for _, c := range cs {f(c)}}//找到所有符合给定标准的汽车func (cs Cars) FindAll(f func(car *Car) bool) Cars {cars := make([]*Car, 0)cs.Process(func(c *Car) {if f(c) {cars = append(cars, c)}})return cars}//处理汽车并创建新数据func (cs Cars) Map(f func(car *Car) Any) []Any {result := make([]Any, len(cs))ix := 0cs.Process(func(c *Car) {result[ix] = f(c)ix++})return result}//func MakeSortedAppender(manufacturers []string) (func(car *Car), map[string]Cars) {//准备排序车的mapsortedCars := make(map[string]Cars)for _, m := range manufacturers {sortedCars[m] = make([]*Car, 0)}sortedCars["Default"] = make([]*Car, 0)//准备appender函数appender := func(c *Car) {if _, ok := sortedCars[c.Manufacturer]; ok {sortedCars[c.Manufacturer] = append(sortedCars[c.Manufacturer], c)} else {sortedCars["Default"] = append(sortedCars["Defaut"], c)}}return appender, sortedCars}func main() {//make some carsford := &Car{"Fiesta", "Ford", 2008}bmw := &Car{"XL 450", "BMW", 2011}merc := &Car{"D600", "Mercedes", 2009}bwm2 := &Car{"X 800", "BMW", 2008}//queryallCars := Cars([]*Car{ford, bmw, merc, bwm2})allNewBmws := allCars.FindAll(func(car *Car) bool {return (car.Manufacturer == "BMW") && (car.BuildYear > 2010)})fmt.Println("AllCars: ", allCars)fmt.Println("New BMWs: ", allNewBmws)manufacturers := []string{"Ford", "Aston Martin", "Land Rover", "BMW", "Jaguar"}sortedAppender, sortedCars := MakeSortedAppender(manufacturers)allCars.Process(sortedAppender)fmt.Println("Map sortedCars: ", sortedCars)BMWCount := len(sortedCars["BMW"])fmt.Println("We have ", BMWCount, " BMWs")}
