当一只鸟走路像鸭子,游泳像鸭子,叫起来也像鸭子,那么我们就认为它就是鸭子。
Duck typing 的理念因此比喻得名。
Golang 通过 interface 实现 duck typing。 Effective Go 文章中这样描述 interface: interface
指定了一种描述对象行为的方法:如果某样东西可以做这件事,这样东西就可以用在这里。
再具体讲, 就是当某个变量的类型实现了某个接口的所有方法 (这个时候可以称该类型实现
满足该接口) ,那么这个变量就能用在要求这个接口的地方。
package mainimport ( "reflect" "fmt")type Test struct {}func (this *Test)test() { fmt.Println("in test()")}type Tester interface { test()}func MakeTest1(v Tester) { fmt.Printf("\nIn Maketest1\n") v.(Tester).test()}func MakeTest2(v interface{}) { fmt.Printf("\nIn Maketest2\n") v.(Tester).test()}func main() { t := new(Test) var ti Tester ti = t ti.test() // 接口类型断言 // value为Test类型的对象 // 是ti的值 value := ti.(Tester) fmt.Printf("\n方式1:\n") fmt.Println(reflect.TypeOf(value)) value.test() // v是ti的值,是Test类型 // Tester是接口类型 if v, ok := ti.(Tester); ok { fmt.Printf("\n方式2:\n") fmt.Println(reflect.TypeOf(v)) v.test() } // switch type专用组合 // 如果需要在if中判断可以用上面的形式 switch t := ti.(type) { case Tester: fmt.Printf("\n方式3:\n") fmt.Println("Tester") fmt.Println(reflect.TypeOf(t)) t.test() default: fmt.Println("Unknow") } // 传递Test结构变量 // 因为Test实现了Tester接口 MakeTest1(t) // 传递Tester接口变量 MakeTest1(ti) // 传递Test结构变量 // 因为Test实现了interface{}接口 MakeTest2(t) // 传递Tester接口变量 // 因为任何类型都实现了interface{} MakeTest2(ti)}
运行结果:
in test()方式1:*main.Testin test()方式2:*main.Testin test()方式3:Tester*main.Testin test()In Maketest1in test()In Maketest1in test()In Maketest2in test()In Maketest2in test()
Golang 里面有个空的接口 interface{}, 大括号里看上去什么也没有, 但认为它有一个空
的方法;Golang 里的每一种类型或者你自定义的类型,不管有没有添加了什么具体的方法,
都认为有一个空的方法。因此每种类型自动实现了 interface{}接口,要求 interface{}的地方
就可以用任意类型的变量。