本篇內(nèi)容介紹了“Go interface怎么使用”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

員工經(jīng)過(guò)長(zhǎng)期磨合與沉淀,具備了協(xié)作精神,得以通過(guò)團(tuán)隊(duì)的力量開(kāi)發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)堅(jiān)持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因?yàn)椤皩W⑺詫I(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡(jiǎn)單”。公司專注于為企業(yè)提供網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、微信公眾號(hào)開(kāi)發(fā)、電商網(wǎng)站開(kāi)發(fā),成都微信小程序,軟件按需求定制開(kāi)發(fā)等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。
簡(jiǎn)單的說(shuō),interface是一組method的組合,我們通過(guò)interface來(lái)定義對(duì)象的一組行為。
interface類型定義了一組方法,如果某個(gè)對(duì)象實(shí)現(xiàn)了某個(gè)接口的所有方法,則此對(duì)象就實(shí)現(xiàn)了此接口。詳細(xì)的語(yǔ)法參考下面這個(gè)例子
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段Human
school string
loan float32
}
type Employee struct {
Human //匿名字段Human
company string
money float32
}
//Human對(duì)象實(shí)現(xiàn)Sayhi方法
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
// Human對(duì)象實(shí)現(xiàn)Sing方法
func (h *Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
}
//Human對(duì)象實(shí)現(xiàn)Guzzle方法
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// Employee重載Human的Sayhi方法
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //此句可以分成多行
}
//Student實(shí)現(xiàn)BorrowMoney方法
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (again and again and...)
}
//Employee實(shí)現(xiàn)SpendSalary方法
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount // More vodka please!!! Get me through the day!
}
// 定義interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}通過(guò)上面的代碼我們可以知道,interface可以被任意的對(duì)象實(shí)現(xiàn)。我們看到上面的Men interface被Human、Student和Employee實(shí)現(xiàn)。同理,一個(gè)對(duì)象可以實(shí)現(xiàn)任意多個(gè)interface,例如上面的Student實(shí)現(xiàn)了Men和YoungChap兩個(gè)interface。
最后,任意的類型都實(shí)現(xiàn)了空interface(我們這樣定義:interface{}),也就是包含0個(gè)method的interface。
那么interface里面到底能存什么值呢?如果我們定義了一個(gè)interface的變量,那么這個(gè)變量里面可以存實(shí)現(xiàn)這個(gè)interface的任意類型的對(duì)象。例如上面例子中,我們定義了一個(gè)Men interface類型的變量m,那么m里面可以存Human、Student或者Employee值。
因?yàn)閙能夠持有這三種類型的對(duì)象,所以我們可以定義一個(gè)包含Men類型元素的slice,這個(gè)slice可以被賦予實(shí)現(xiàn)了Men接口的任意結(jié)構(gòu)的對(duì)象,這個(gè)和我們傳統(tǒng)意義上面的slice有所不同。
讓我們來(lái)看一下下面這個(gè)例子:
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段
school string
loan float32
}
type Employee struct {
Human //匿名字段
company string
money float32
}
//Human實(shí)現(xiàn)SayHi方法
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
//Human實(shí)現(xiàn)Sing方法
func (h Human) Sing(lyrics string) {
fmt.Println("La la la la...", lyrics)
}
//Employee重載Human的SayHi方法
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone)
}
// Interface Men被Human,Student和Employee實(shí)現(xiàn)
// 因?yàn)檫@三個(gè)類型都實(shí)現(xiàn)了這兩個(gè)方法
type Men interface {
SayHi()
Sing(lyrics string)
}
func main() {
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
tom := Employee{Human{"Tom", 37, "222-444-XXX"}, "Things Ltd.", 5000}
//定義Men類型的變量i
var i Men
//i能存儲(chǔ)Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i也能存儲(chǔ)Employee
i = tom
fmt.Println("This is tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
//定義了slice Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men, 3)
//這三個(gè)都是不同類型的元素,但是他們實(shí)現(xiàn)了interface同一個(gè)接口
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x{
value.SayHi()
}
}通過(guò)上面的代碼,你會(huì)發(fā)現(xiàn)interface就是一組抽象方法的集合,它必須由其他非interface類型實(shí)現(xiàn),而不能自我實(shí)現(xiàn), Go通過(guò)interface實(shí)現(xiàn)了duck-typing:即"當(dāng)看到一只鳥(niǎo)走起來(lái)像鴨子、游泳起來(lái)像鴨子、叫起來(lái)也像鴨子,那么這只鳥(niǎo)就可以被稱為鴨子"。
空interface(interface{})不包含任何的method,正因?yàn)槿绱耍械念愋投紝?shí)現(xiàn)了空interface。空interface對(duì)于描述起不到任何的作用(因?yàn)樗话魏蔚膍ethod),但是空interface在我們需要存儲(chǔ)任意類型的數(shù)值的時(shí)候相當(dāng)有用,因?yàn)樗梢源鎯?chǔ)任意類型的數(shù)值。它有點(diǎn)類似于C語(yǔ)言的void*類型。
// 定義a為空接口
var a interface{}
var i int = 5
s := "Hello world"
// a可以存儲(chǔ)任意類型的數(shù)值
a = i
a = s一個(gè)函數(shù)把interface{}作為參數(shù),那么他可以接受任意類型的值作為參數(shù),如果一個(gè)函數(shù)返回interface{},那么也就可以返回任意類型的值。是不是很有用啊!
interface的變量可以持有任意實(shí)現(xiàn)該interface類型的對(duì)象,這給我們編寫函數(shù)(包括method)提供了一些額外的思考,我們是不是可以通過(guò)定義interface參數(shù),讓函數(shù)接受各種類型的參數(shù)。
舉個(gè)例子:fmt.Println是我們常用的一個(gè)函數(shù),但是你是否注意到它可以接受任意類型的數(shù)據(jù)。打開(kāi)fmt的源碼文件,你會(huì)看到這樣一個(gè)定義:
type Stringer interface {
String() string
}也就是說(shuō),任何實(shí)現(xiàn)了String方法的類型都能作為參數(shù)被fmt.Println調(diào)用,讓我們來(lái)試一試
package main
import (
"fmt"
"strconv"
)
type Human struct {
name string
age int
phone string
}
// 通過(guò)這個(gè)方法 Human 實(shí)現(xiàn)了 fmt.Stringer
func (h Human) String() string {
return "?"+h.name+" - "+strconv.Itoa(h.age)+" years - ? " +h.phone+"?"
}
func main() {
Bob := Human{"Bob", 39, "000-7777-XXX"}
fmt.Println("This Human is : ", Bob)
}現(xiàn)在我們?cè)倩仡櫼幌虑懊娴腂ox示例,你會(huì)發(fā)現(xiàn)Color結(jié)構(gòu)也定義了一個(gè)method:String。其實(shí)這也是實(shí)現(xiàn)了fmt.Stringer這個(gè)interface,即如果需要某個(gè)類型能被fmt包以特殊的格式輸出,你就必須實(shí)現(xiàn)Stringer這個(gè)接口。如果沒(méi)有實(shí)現(xiàn)這個(gè)接口,fmt將以默認(rèn)的方式輸出。
//實(shí)現(xiàn)同樣的功能
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("The biggest one is", boxes.BiggestsColor())注:實(shí)現(xiàn)了error接口的對(duì)象(即實(shí)現(xiàn)了Error() string的對(duì)象),使用fmt輸出時(shí),會(huì)調(diào)用Error()方法,因此不必再定義String()方法了。
我們知道interface的變量里面可以存儲(chǔ)任意類型的數(shù)值(該類型實(shí)現(xiàn)了interface)。那么我們?cè)趺捶聪蛑肋@個(gè)變量里面實(shí)際保存了的是哪個(gè)類型的對(duì)象呢?目前常用的有兩種方法:
Comma-ok斷言
Go語(yǔ)言里面有一個(gè)語(yǔ)法,可以直接判斷是否是該類型的變量: value, ok = element.(T),這里value就是變量的值,ok是一個(gè)bool類型,element是interface變量,T是斷言的類型。
如果element里面確實(shí)存儲(chǔ)了T類型的數(shù)值,那么ok返回true,否則返回false。
讓我們通過(guò)一個(gè)例子來(lái)更加深入的理解。
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List [] Element
type Person struct {
name string
age int
}
//定義了String方法,實(shí)現(xiàn)了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)
}
}
}是不是很簡(jiǎn)單啊,同時(shí)你是否注意到了多個(gè)if里面,還記得我前面介紹流程時(shí)講過(guò),if里面允許初始化變量。
也許你注意到了,我們斷言的類型越多,那么if else也就越多,所以才引出了下面要介紹的switch。
switch測(cè)試
最好的講解就是代碼例子,現(xiàn)在讓我們重寫上面的這個(gè)實(shí)現(xiàn)
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)
}
}
}這里有一點(diǎn)需要強(qiáng)調(diào)的是:element.(type)語(yǔ)法不能在switch外的任何邏輯里面使用,如果你要在switch外面判斷一個(gè)類型就使用comma-ok。
Go里面真正吸引人的是它內(nèi)置的邏輯語(yǔ)法,就像我們?cè)趯W(xué)習(xí)Struct時(shí)學(xué)習(xí)的匿名字段,多么的優(yōu)雅啊,那么相同的邏輯引入到interface里面,那不是更加完美了。如果一個(gè)interface1作為interface2的一個(gè)嵌入字段,那么interface2隱式的包含了interface1里面的method。
我們可以看到源碼包c(diǎn)ontainer/heap里面有這樣的一個(gè)定義
type Interface interface {
sort.Interface //嵌入字段sort.Interface
Push(x interface{}) //a Push method to push elements into the heap
Pop() interface{} //a Pop elements that pops elements from the heap
}我們看到sort.Interface其實(shí)就是嵌入字段,把sort.Interface的所有method給隱式的包含進(jìn)來(lái)了。也就是下面三個(gè)方法:
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}另一個(gè)例子就是io包下面的 io.ReadWriter ,它包含了io包下面的Reader和Writer兩個(gè)interface:
// io.ReadWriter
type ReadWriter interface {
Reader
Writer
}Go語(yǔ)言實(shí)現(xiàn)了反射,所謂反射就是能檢查程序在運(yùn)行時(shí)的狀態(tài)。我們一般用到的包是reflect包。如何運(yùn)用reflect包,官方的這篇文章詳細(xì)的講解了reflect包的實(shí)現(xiàn)原理,laws of reflection
使用reflect一般分成三步,下面簡(jiǎn)要的講解一下:要去反射是一個(gè)類型的值(這些值都實(shí)現(xiàn)了空interface),首先需要把它轉(zhuǎn)化成reflect對(duì)象(reflect.Type或者reflect.Value,根據(jù)不同的情況調(diào)用不同的函數(shù))。這兩種獲取方式如下:
t := reflect.TypeOf(i) //得到類型的元數(shù)據(jù),通過(guò)t我們能獲取類型定義里面的所有元素 v := reflect.ValueOf(i) //得到實(shí)際的值,通過(guò)v我們獲取存儲(chǔ)在里面的值,還可以去改變值
轉(zhuǎn)化為reflect對(duì)象之后我們就可以進(jìn)行一些操作了,也就是將reflect對(duì)象轉(zhuǎn)化成相應(yīng)的值,例如
tag := t.Elem().Field(0).Tag //獲取定義在struct里面的標(biāo)簽 name := v.Elem().Field(0).String() //獲取存儲(chǔ)在第一個(gè)字段里面的值
獲取反射值能返回相應(yīng)的類型和數(shù)值
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())最后,反射的話,那么反射的字段必須是可修改的,我們前面學(xué)習(xí)過(guò)傳值和傳引用,這個(gè)里面也是一樣的道理。反射的字段必須是可讀寫的意思是,如果下面這樣寫,那么會(huì)發(fā)生錯(cuò)誤
var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.1)
如果要修改相應(yīng)的值,必須這樣寫
var x float64 = 3.4 p := reflect.ValueOf(&x) v := p.Elem() v.SetFloat(7.1)
“Go interface怎么使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
本文標(biāo)題:Gointerface怎么使用
轉(zhuǎn)載注明:http://chinadenli.net/article24/ihjhje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、面包屑導(dǎo)航、網(wǎng)站營(yíng)銷、網(wǎng)站收錄、服務(wù)器托管、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)