Go 語言 介面(Interface)

來源:互聯網
上載者:User

What is Interface type in Go ?

GoLang官網language specification文檔對interface type的概念說明如下:

An interface type specifies a method set called its interface.
A variable of interface type can store a value of any type with a method set that is any superset of the interface.
Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.

Go 語言提供了另外一種資料類型即介面(interface),它把所有的具有共性的方法定義在一起,這些方法只有函數簽名,沒有具體的實現代碼(類似於Java中的抽象函數),任何其他類型只要實現了介面中定義好的這些方法,那麼就說 這個類型實現(implement)了這個介面

介面的通用定義方式如下

/* 定義介面 */type interface_name interface {   method_name1 [return_type]   method_name2 [return_type]   method_name3 [return_type]   ...   method_namen [return_type]}/* 定義xxx資料結構類型 */type struct_name xxx/* 實現介面方法 */func (struct_name_variable struct_name) method_name1() [return_type] {   /* 方法實現 */}    ...func (struct_name_variable struct_name) method_namen() [return_type] {   /* 方法實現*/}

上面使用type聲明一個名為 interface_name 的介面,interface類型是可以定義為變數的,比如

var  name  interface_name

介面在Go語言中是參考型別,因此在上面定義的介面變數中,name是一個指標

我們依照上面的介面通用定義方式,定義以下執行個體

//定義電話介面type Phone interface {   call()}//自訂結構體type Nokia struct {}//實現介面方法func (nokia Nokia)call()  {   fmt.Println("I am Nokia, I can call you!")}func main() {   var  phone Phone   phone = new(Nokia)   phone.call()}

call()是Phone介面定義好的一個方法,然後由Nokia實現了介面中這個方法,所以Nokia 實現了 Phone介面。

Interface“多態”特性執行個體
interface{}類型的變數,可以使用任何類型的值來賦值

func main() {   var a interface{}  = 123   var b interface{}  = "abc"   var c interface{}  = 1.23   fmt.Println(a,b,c)}-----output----123 abc 1.23

在Go語言中內建的標準Packages中,有很多地方利用 interface 來處理未知資料類型,比如我們常用的fmt包,以fmt.Println為例,它的函數簽名格式如下

// Println formats using the default formats for its operands and writes to standard output.// Spaces are always added between operands and a newline is appended.// It returns the number of bytes written and any write error encountered.func Println(a ...interface{}) (n int, err error) {   return Fprintln(os.Stdout, a...)}

fmt包的Println函數需要傳入interface類型的可變長參數,該函數在實現底層的列印行為時,要求傳入的可變長參數實現了fmt包中定義的Stringer介面。
Stringer介面類型描述如下:

// Stringer is implemented by any value that has a String method,// which defines the ``native'' format for that value.// The String method is used to print values passed as an operand// to any format that accepts a string or to an unformatted printer// such as Print.type Stringer interface {   String() string}

所以,自訂類型想要調用fmt.Printf()做格式化列印,那隻需實現Stringer介面就行。

舉例說明:自訂輸出類型格式
定義一個map集合,並迴圈輸出map的元素

type PersonInfo struct {   ID string   Name string   address string}func main() {   //建立集合   var myMap map[string] PersonInfo   //初始化集合   myMap = make(map[string]PersonInfo)   //向map中添加元素   myMap ["1"] = PersonInfo{"1","zhangsan","shanghai"}   myMap ["2"] = PersonInfo{"2","wangwu","beijing"}   myMap ["3"] = PersonInfo{"3","lisi","tianjin"}   //迴圈輸出   for num,person := range myMap{      fmt.Printf("%v: %v\n",num,person)   }}----------output------------1: {1 zhangsan shanghai}2: {2 wangwu beijing}3: {3 lisi tianjin}

現在我們要自訂map集合輸出的格式,比如輸出第一個元素:1: {1&zhangsan&shanghai},因此 PersonInfo 需要實現Stringer介面

//自訂類型需要實現Stringer介面func (pInfo PersonInfo)String()string  {   return fmt.Sprintf("%v&%v&%v",pInfo.ID,pInfo.Name,pInfo.address)}

最終自訂格式化輸出為:

1: 1&zhangsan&shanghai2: 2&wangwu&beijing3: 3&lisi&tianjin

介面嵌入
Go語言的介面對嵌入支援的非常好,介面可以嵌入其他的介面,效果就像在介面中 直接添加被嵌入介面的方法一樣。

type HavingFoot interface {   Foot()}type HavingEye interface {   Eye()}type HuMan interface {   HavingEye   HavingFoot}

HuMan介面嵌入了 HavingFoot 介面與 HavingEye 介面,就相當於HuMan介面包含了HavingFoot 介面與 HavingEye 介面中所有的方法。如果要實現HuMan介面,就要定義 Foot() 與 Eye() 方法。

類型猜測
如果有兩個類型都實現了同一介面,那麼這兩個類型變數A,B都可以賦值給這個介面類型的變數C(類似於Java繼承中的向上傳遞),然後這個介面類型的變數C,可以去尋找是類型變數A還是B給它賦值的,查詢通用格式如下:

value,ok := obj.(struct)

struct:需要猜測的類型A或B value:傳回型別變數A或B
ok:查詢結果 obj:介面類型的變數C

類型猜測執行個體

//定義電話介面type Phone interface {   call()}//自訂結構體type Nokia struct {}type Iphone struct {}//實現介面方法func (nokia Nokia)call()  {   fmt.Println("I am Nokia, I can call you!")}func (iphone  Iphone)call()  {   fmt.Println("I am Iphone, I can call you!")}func main() {   //將兩個子類賦值給介面   var phone1 Phone = Nokia{}   var phone2 Phone = Iphone{}   //判斷phone1是不是Nokia賦值給它的   if values,ok := phone1.(Nokia);ok {      values.call()   }   //判斷phone2是不是Nokia賦值給它的   if values,ok := phone2.(Iphone);ok {      values.call()   }}

推薦閱讀:https://studygolang.com/articles/2652

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.