Golang interface接口全面理解(一)

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

什麼是interface

    在面向對象編程中,能夠這麼說:「接口定義了對象的行爲」, 那麼具體的實現行爲就取決於對象了。oop

    在Go中,接口是一組方法簽名。當一個類型爲接口中的全部方法提供定義時,它被稱爲實現該接口。它與oop很是類似。接口指定類型應具備的方法,類型決定如何實現這些方法。spa

建立和實現interface

在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)
}
相關文章
相關標籤/搜索