There are three kinds of time: the future is late, and now it is flying like an arrow. The past will never stand still.編程
時間的步伐有三種:將來姍姍來遲,如今像箭通常飛逝,過去永遠靜立不動。app
在面向對象編程中,能夠這麼說:「接口定義了對象的行爲」, 那麼具體的實現行爲就取決於對象了。oop
在Go中,接口是一組方法簽名。當一個類型爲接口中的全部方法提供定義時,它被稱爲實現該接口。它與oop很是類似。接口指定類型應具備的方法,類型決定如何實現這些方法。spa
在Golang中只要實現了接口定義的方法,就是(JAVA implement)實現了該interface code
package main import ( "fmt" ) //定義interface type VowelsFinder interface { FindVowels() []rune } type MyString string //實現接口 func (ms MyString) FindVowels() []rune { var vowels []rune for _, rune := range ms { if rune == 'a' || rune == 'e' || rune == 'i' || rune == 'o' || rune == 'u' { vowels = append(vowels, rune) } } return vowels } func main() { name := MyString("Sam Anderson") // 類型轉換 var v VowelsFinder // 定義一個接口類型的變量 v = name fmt.Printf("Vowels are %c", v.FindVowels()) }
爲何說是實際用途呢? 若是咱們我上面code中的對象
fmt.Printf("Vowels are %c", v.FindVowels())
替換爲接口
fmt.Printf("Vowels are %c", name.FindVowels())
程序一樣的輸出,而沒有使用咱們定義的接口。(v變量刪除定義)three
下面咱們經過案例解釋:字符串
假設某公司有兩個員工,一個普通員工和一個高級員工, 可是基本薪資是相同的,高級員工多拿獎金。計算公司爲員工的總開支。string
package main import ( "fmt" ) // 薪資計算器接口 type SalaryCalculator interface { CalculateSalary() int } // 普通挖掘機員工 type Contract struct { empId int basicpay int } // 有藍翔技校證的員工 type Permanent struct { empId int basicpay int jj int // 獎金 } func (p Permanent) CalculateSalary() int { return p.basicpay + p.jj } func (c Contract) CalculateSalary() int { return c.basicpay } // 總開支 func totalExpense(s []SalaryCalculator) { expense := 0 for _, v := range s { expense = expense + v.CalculateSalary() } fmt.Printf("總開支 $%d", expense) } func main() { pemp1 := Permanent{1,3000,10000} pemp2 := Permanent{2, 3000, 20000} cemp1 := Contract{3, 3000} employees := []SalaryCalculator{pemp1, pemp2, cemp1} totalExpense(employees) }
體驗一下使用接口的美感吧!
一個接口能夠被認爲是由一個元組(類型,值)在內部表示的。type是接口的基礎具體類型,value是具體類型的值。
package main import ( "fmt" ) type Test interface { Tester() } type MyFloat float64 func (m MyFloat) Tester() { fmt.Println(m) } func describe(t Test) { fmt.Printf("Interface 類型 %T , 值: %v\n", t, t) } func main() { var t Test f := MyFloat(89.7) t = f describe(t) t.Tester() }
輸出:
Interface 類型 main.MyFloat , 值: 89.7
89.7
具備0個方法的接口稱爲空接口。它表示爲interface {}。因爲空接口有0個方法,全部類型都實現了空接口。
package main import ( "fmt" ) func describe(i interface{}) { fmt.Printf("Type = %T, value = %v\n", i, i) } func main() { // 任何類型的變量傳入均可以 s := "Hello World" i := 55 strt := struct { name string }{ name: "Naveen R", } describe(s) describe(i) describe(strt) }
類型斷言用於提取接口的基礎值,語法:i.(T)
package main import( "fmt" ) func assert(i interface{}){ s:= i.(int) fmt.Println(s) } func main(){ var s interface{} = 55 assert(s) }
程序打印的是int值, 可是若是咱們給s 變量賦值的是string類型,程序就會panic。
因此能夠將以上程序改寫爲:
package main import ( "fmt" ) func assert(i interface{}) { v, ok := i.(int) fmt.Println(v, ok) } func main() { var s interface{} = 56 assert(s) var i interface{} = "Steven Paul" assert(i) }
若是 i 的值是int類型, 那麼v就是i 對應的值, ok就是true。不然ok爲false,程序並不會panic。
類型判斷的語法相似於類型斷言。在類型斷言的語法i.(type)中,類型type應該由類型轉換的關鍵字type替換。讓咱們看看它如何在下面的程序中起做用。
package main import ( "fmt" ) func findType(i interface{}) { switch i.(type) { case string: fmt.Printf("String: %s\n", i.(string)) case int: fmt.Printf("Int: %d\n", i.(int)) default: fmt.Printf("Unknown type\n") } } func main() { findType("Naveen") findType(77) findType(89.98) }
還能夠將類型與接口進行比較。若是咱們有一個類型而且該類型實現了一個接口,那麼能夠將它與它實現的接口進行比較。
package main import "fmt" type Describer interface { Describe() } type Person struct { name string age int } func (p Person) Describe() { fmt.Printf("%s is %d years old", p.name, p.age) } func findType(i interface{}) { switch v := i.(type) { case Describer: v.Describe() default: fmt.Printf("unknown type\n") } } func main() { findType("Naveen") p := Person{ name: "Naveen R", age: 25, } findType(p) }
輸出:
unknown type Naveen R is 25 years old
最後,留一個小問題,猜測一下,下面程序的輸出結果:
package main import "fmt" type Describer interface { Describe() } type St string func (s St) Describe() { fmt.Println("被調用le!") } func findType(i interface{}) { switch v := i.(type) { case Describer: v.Describe() case string: fmt.Println("String 變量") default: fmt.Printf("unknown type\n") } } func main() { findType("Naveen") st := St("個人字符串") findType(st) }