當一隻鳥走路像鴨子,游泳像鴨子,叫起來也像鴨子,那麼咱們就認爲它就是鴨子。this
Duck typing 的理念所以比喻得名。spa
Golang 經過 interface 實現 duck typing。 Effective Go 文章中這樣描述 interface: interfacecode
指定了一種描述對象行爲的方法:若是某樣東西能夠作這件事,這樣東西就能夠用在這裏。對象
再具體講, 就是當某個變量的類型實現了某個接口的全部方法 (這個時候能夠稱該類型實現blog
知足該接口) ,那麼這個變量就能用在要求這個接口的地方。接口
package main import ( "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) }
運行結果:ip
in test() 方式1: *main.Test in test() 方式2: *main.Test in test() 方式3: Tester *main.Test in test() In Maketest1 in test() In Maketest1 in test() In Maketest2 in test() In Maketest2 in test()
Golang 裏面有個空的接口 interface{}, 大括號裏看上去什麼也沒有, 但認爲它有一個空get
的方法;Golang 裏的每一種類型或者你自定義的類型,無論有沒有添加了什麼具體的方法,it
都認爲有一個空的方法。所以每種類型自動實現了 interface{}接口,要求 interface{}的地方class
就能夠用任意類型的變量。