golang 接口

接口

一組method 簽名的組合 通過interface 來定義對象的一組行爲
interface 就是一組抽象方法的集合

interface 類型

interface 類型定義了一組方法, 如果某個對象實現了某個接口中的方法, 則此對象就實現了此接口

interface 值

如果定義了一個interface 變量, 那麼這個變量裏面可以存實現這個interface的任意類型的對象。

空interface

interface{} 不包含任何的method
所有的類型都實現了空的interface

空interface 可以用來存儲任意類型的值
一個函數把interface{} 作爲參數 可以接受任意類型的值作爲參數, 如果一個函數返回interface{ 那麼也就可以返回任意類型的值

interface 變量存儲的類型

interface 變量中國可以存儲任意類型對象的數值(前提是實現了 interface)
反過來要想通過這個變量裏面 實際保存的是哪個類型的對象呢 ?

  1. 斷言 comma-ok 斷言

    value, ok = element.(T)
    value 變量的值,ok 是bool 類型, element 是 interface 變量, T 是斷言的類型
    如果element 裏面確實存儲了T 類型的數值, 那麼ok 返回true 否則false

package main

	import (
		"fmt"
		"strconv"
	)

	type Element interface{}
	type List [] Element

	type Person struct {
		name string
		age int
	}

	//定義了String方法,實現了fmt.Stringer
	func (p Person) String() string {
		return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
	}

	func main() {
		list := make(List, 3)
		list[0] = 1 // an int
		list[1] = "Hello" // a string
		list[2] = Person{"Dennis", 70}

		for index, element := range list {
			if value, ok := element.(int); ok {
				fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
			} else if value, ok := element.(string); ok {
				fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
			} else if value, ok := element.(Person); ok {
				fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
			} else {
				fmt.Printf("list[%d] is of a different type\n", index)
			}
		}
	}

swith 測試
element.(type)
這種方式需要注意:
element.(type) 不能再switch 外的任何邏輯裏面使用, 如果再外面使用就使用 斷言comma-ok的方式

package main

	import (
		"fmt"
		"strconv"
	)

	type Element interface{}
	type List [] Element

	type Person struct {
		name string
		age int
	}

	//打印
	func (p Person) String() string {
		return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
	}

	func main() {
		list := make(List, 3)
		list[0] = 1 //an int
		list[1] = "Hello" //a string
		list[2] = Person{"Dennis", 70}

		for index, element := range list{
			switch value := element.(type) {
				case int:
					fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
				case string:
					fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
				case Person:
					fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
				default:
					fmt.Println("list[%d] is of a different type", index)
			}
		}
	}

非侵入式接口

只需要實現接口中的所有方法 則就實現了這個接口

好處 :
1 go 語言的標準庫 再也不需要回執類庫的繼承樹圖
2實現類的時候 只需要關心自己實現哪些方法, 不需要再糾結接口需要才分的多細才合理
3 不用爲了實現一個接口而導入一個包。 多導入一個包 就以爲着更多的耦合。

接口賦值

接口賦值在go 語言中 分爲如下兩種情況
1 將對象實例賦值爲接口
2 將接口賦值給另一個接口

go語言中, 只要兩個接口擁有相同的方法列表 (次序不同不要緊) 那麼他們就是相同的, 可以相互賦值。

接口賦值 不需要兩個接口必須等價。 如果接口A的方法列表 是B接口方法列表的子集, 那麼接口B 可以賦值給接口A。

接口查詢

var file1 Writer = …
if file5, ok := file1.(two.IStream); ok {

}

if 語句檢查file1 接口指向 的對象實例是否實現two.IStream 接口, 如果實現了 執行特定的代碼

接口查詢 是否成功 要在運行期才能夠確定
接口賦值, 編譯器只需要通過靜態類型檢查就可以

Any 類型

go 中任何對象實例都滿足空接口interface interface{ 都可以指向任何對象的Any 類型}

var v1 interface{} = 1 // 將int類型賦值給interface{}
var v2 interface{} = “abc” // 將string類型賦值給interface{}
var v3 interface{} = &v2 // 將*interface{}類型賦值給interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}

注意地方
如果接受方法 使用的是指針 的話 在判斷類型的時候
_,ok := talk.(*myTalk)

類型斷言

接口類型向普通類型的轉換稱爲類型斷言 (運行時綁定)

func echoArray(a interface{}){
    b,_:=a.([]int)//通過斷言實現類型轉換
  for _,v:=range b{
    fmt.Print(v," ")
  }
  fmt.Println()
  return
} 

// 使用這樣判斷
b,ok:=a.([]int)
if ok{
    ...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章