八、深入Go 编程语言接口
@Author:Runsen
學習過Java,大家或多或少了解接口。接口是一種類型,它指定一個方法集,所有方法為接口類型就被認為是該接口。
文章目錄
- 接口
- 接口內部實現
- 指針方法值方法
- 空接口
接口
在Go語言中,一個接口類型總是代表著某一種類型(即所有實現它的類型)的行為。一個接口類型的聲明通常會包含關鍵字type、類型名稱、關鍵字interface以及由花括號包裹的若干方法聲明。go 使用 type 關鍵字來定義接口,接口的聲明類似于結構體,使用類型別名且需要關鍵字 interface,語法如下。代碼來源:菜鳥教程。
type Name interface {Method1(param_list) return_typeMethod2(param_list) return_type... }go 中的接口,這個概念實際上是比較難懂的,來看一個demo:
package mainimport "fmt"type Person interface {getName() string }type student struct {Name string sex string }var stu = student{"Runsen","男"}func (stu student) getName() string {return stu.Name } // 這樣student類型就實現了Person接口type teacher struct {Name string sex string }var tea = teacher{"Runsen","男"}func (tea teacher) getName() string{return tea.Name } // 這樣teacher類型就實現了Person接口func main() {fmt.Println(stu.getName()) //Runsenfmt.Println(tea.getName()) //Runsen }上面的代碼定義了接口類型 Person ,接口中包含了一個不帶參數、返回值為 string的方法 getName()。任何實現了方法 getName() 的類型 student和teacher,我們就說它實現了接口 Person 。
接口內部實現
接口內部的實現:
type iface struce{tab *iTabledata unsafe.Pointer }接口結構是包含兩個字段的數據結構,第一個包含一個指向內部表的指針,這個內部表叫做iTable,包含子所存儲的值的類型信息。iTable包含了已存儲的值的類型信息已經值關聯的一組方法。第二個字段指向存儲值的指針,指向賦值的這個對象。
從內部實現來看,接口本身也是一種結構類型,只是編譯器會對其做很多的限制。
- 不能有自己的字段
- 不能定義自己的方法
- 只能聲明方法,不能實現
- 可嵌入其他接口類型
這些注意點和Java的接口完全一樣。
指針方法值方法
實現接口有兩種方法。上面我們都是使用值接受者(Value Receiver)來實現接口的。我們同樣可以使用指針接受者(Pointer Receiver)來實現接口。
在此之前,我們需要了解下指針。
指針是存儲變量內存地址的變量,表達了這個變量在內存存儲的位置。就像我們常說:指針指向了變量。
Go 語言的取地址符是 &,放到一個變量前使用就會返回相應變量的內存地址。
package mainimport "fmt"func main() {var a int = 1fmt.Printf("變量的地址: %x\n", &a) // 變量的地址: c0000140b8 }在Go語言中關于指針的操作如下所示。
package mainimport "fmt"func main() {var a int= 1 /* 聲明實際變量 */var ip *int /* 聲明指針變量 */ip = &a /* 指針變量的存儲地址 */fmt.Printf("a 變量的地址是: %x\n", &a ) //a 變量的地址是: c0000140b8/* 指針變量的存儲地址 */fmt.Printf("ip 變量儲存的指針地址: %x\n", ip ) //ip 變量儲存的指針地址: c0000140b8/* 使用指針訪問值 */fmt.Printf("*ip 變量的值: %d\n", *ip ) //*ip 變量的值: 1 }在函數接收者,可以使用指針方法和值方法。區別在于,用指針類型作為接收者,可以在函數/方法內部修改這個接收者的數據,而用值類型作為接收者,在函數/方法內部不能修改原接收者的數據。
接收者可以是指針類型,也可以是值類型,它們到底有什么區別?一開始學Go語言的時候,我也一頭霧水。看下面的例子就明白了:
package main import "fmt"type user struct {name stringage int } // 值的 func (u user) PrintName() {fmt.Println(u.name) } // 指針的 func (u *user) PrintAge() {fmt.Println(u.age) } func main() { var Runsen *user // 潤森是指針類型的Runsen = &user{"Runsen", 20} // 正常輸出無誤Runsen.PrintName() // zhangsanRunsen.PrintAge() // 10var maoli user // 毛利是值類型maoli = user{"Maoli", 20} // 正常輸出無誤maoli.PrintName() // lisimaoli.PrintAge() // 20// 以值的方式調用 一個定義在指針類型下的方法時,會隱式的轉換值到指針,例中maoli.PrintAge() 就是這樣 // 以指針的方式調用 一個定義在值類型下的方法時,會隱式的轉換指針到值,例中Runsen.PrintName() 就是這樣 // 相同:無論定義在哪種類型下,都可以訪問到。 // 區別:只有定義在指針類型下的方法可以修改原變量的內容 }指針類型的接收者之所以需要指針,就是因為它要改變原對象的值。 在上面的例子中,調用user的SetName方法時,編譯器會幫你把user的指針傳遞給SetName方法。
空接口
一個不包含任何方法的接口,稱之為空接口,形如:interface{}。因為空接口不包含任何方法,所以任何類型都默認實現了空接口。
舉個例子,fmt 包中的 Println() 函數,可以接收多種類型的值,比如:int、string、array等。為什么,因為它的形參就是接口類型,可以接收任意類型的值。
下面就是Println接口源碼
func Println(a ...interface{}) (n int, err error) {}空接口表示為 interface{}。由于空接口沒有方法,因此所有類型都實現了空接口。
package mainimport "fmt"func describe(i interface{}) { fmt.Printf("Type = %T, value = %v\n", i, i) }func main() { s := "Hello World"describe(s) //Type = string, value = Hello Worldi := 1 describe(i) // Type = int, value = 1strt := struct {name string}{name: "Runsen",}describe(strt) //Type = struct { name string }, value = {Runsen}}感謝各位的閱讀,文章的目的是分享對知識的理解,技術類文章我都會反復求證以求最大程度保證準確性,若文中出現明顯紕漏也歡迎指出,我們一起在探討中學習。
總結
以上是生活随笔為你收集整理的八、深入Go 编程语言接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 九、Golang并发和线程模型
- 下一篇: 怎么用u盘装电脑驱动程序 用U盘安装电脑