Golang接口的定義與空接口及斷言的使用示例
1. Golang中的接口
在Go語(yǔ)言中接口(interface)是一種類(lèi)型,一種抽象的類(lèi)型。
接口(interface)定義了一個(gè)對(duì)象的行為規(guī)范, 只定義規(guī)范不實(shí)現(xiàn) ,由具體的對(duì)象來(lái)實(shí)現(xiàn)規(guī)范的細(xì)節(jié) 。
實(shí)現(xiàn)接口的條件:
一個(gè)對(duì)象只要全部實(shí)現(xiàn)了接口中的方法 ,那么就實(shí)現(xiàn)了這個(gè)接口。換句話說(shuō),接口就是一個(gè)需要實(shí)現(xiàn)的方法列表。
2. 為什么要使用接口
下面的代碼中定義了貓和狗,然后它們都會(huì)叫,你會(huì)發(fā)現(xiàn)main函數(shù)中明顯有重復(fù)的代碼
如果我們后續(xù)再加上豬、青蛙等動(dòng)物的話,我們的代碼還會(huì)一直重復(fù)下去
那我們能不能把它們當(dāng)成“能叫的動(dòng)物”來(lái)處理呢?
type Cat struct { Name string } func (c Cat) Say() string { return c.Name + ":喵喵喵" } type Dog struct { Name string } func (d Dog) Say() string { return d.Name + ": 汪汪汪" } func main() { c := Cat{Name: "小白貓"} // 小白貓:喵喵喵 fmt.Println(c.Say()) d := Dog{"阿黃"} fmt.Println(d.Say()) // 阿黃: 汪汪汪 } /* 小白貓:喵喵喵 阿黃: 汪汪汪 */
3. 定義一個(gè)Usber接口(從下往上轉(zhuǎn)換)
定義一個(gè) Usber 接口讓 Phone 和 Computer 結(jié)構(gòu)體實(shí)現(xiàn)這個(gè)接口
//1.接口是一個(gè)規(guī)范 type Usber interface { getName() string } //2.如果接口里面有方法的話,必要要通過(guò)結(jié)構(gòu)體或者通過(guò)自定義類(lèi)型實(shí)現(xiàn)這個(gè)接口 type Phone struct { Name string } type Computer struct { Brand string } func (c *Computer) getName() string { return c.Brand } //3.手機(jī)要實(shí)現(xiàn)usb接口的話必須得實(shí)現(xiàn)usb接口中的所有方法 func (p *Phone) getName() string { return p.Name } func main() { p := &Phone{ Name: "華為手機(jī)", } c := &Computer{ Brand: "聯(lián)想電腦", } var p1 Usber // golang中接口就是一個(gè)數(shù)據(jù)類(lèi)型 p1 = p // 表示手機(jī)實(shí)現(xiàn)Usb接口 fmt.Println(p1.getName()) //接口使用場(chǎng)景,處理相同類(lèi)型的數(shù)據(jù) newName := transData(p) newName1 := transData(c) fmt.Println(newName, newName1) } func transData(usber Usber) string { name := usber.getName() return fmt.Sprintf("%s%s", name, "處理后") }
當(dāng)我們要去處理同一數(shù)據(jù)類(lèi)型的時(shí)候這個(gè)數(shù)據(jù)的時(shí)候,比如貓 狗是同一類(lèi)數(shù)據(jù)類(lèi)型。
像k8s的deployment,pod,configmap,secretd等等這些資源的時(shí)候,它都是k8s的一個(gè)資源,在獲取列表的時(shí)候會(huì)對(duì)其做數(shù)據(jù)處理,比如要對(duì)其進(jìn)行數(shù)據(jù)排序,那么只需要對(duì)這個(gè)接口進(jìn)行排序就行了,不需要對(duì)每個(gè)資源都去寫(xiě)一遍排序的方法,那么這樣不是很冗余嗎?
4. 空接口
1. 空接口說(shuō)明
- Golang中空接口也可以直接當(dāng)做類(lèi)型來(lái)使用,可以表示任意類(lèi)型 (泛型概念,最大的特點(diǎn))
- Golang 中的接口可以不定義任何方法,沒(méi)有定義任何方法的接口就是空接口。
- 空接口表示沒(méi)有任何約束,因此任何類(lèi)型變量都可以實(shí)現(xiàn)空接口。
- 空接口在實(shí)際項(xiàng)目中用的是非常多的,用空接口可以表示任意數(shù)據(jù)類(lèi)型
2. 空接口作為函數(shù)的參數(shù)
//空接口作為函數(shù)的參數(shù) func show(a interface{}) { fmt.Printf("值:%v 類(lèi)型:%T\n", a, a) } func main() { show(20) // 值:20 類(lèi)型:int show("你好golang") // 值:你好golang 類(lèi)型:string slice := []int{1, 2, 34, 4} show(slice) // 值:[1 2 34 4] 類(lèi)型:[]int }
printf println是可以接受任何參數(shù)的,func Printf(format string , a ...interface{})可以看到這里可以接受任何空接口類(lèi)型,...類(lèi)似于切片類(lèi)型。
func test(a int, b ...interface{}) { for _, v := range b { fmt.Printf("%v,%T \n", v, v) } } func main() { test(1, "a", 22, []string{"1"}) } a,string 22,int [1],[]string
3. 切片實(shí)現(xiàn)空接口
切片和map是同一類(lèi)型的元素,有了空接口,在同一個(gè)切片同一個(gè)map中就可以將任何類(lèi)型的數(shù)據(jù)放進(jìn)去。
func main() { var slice = []interface{}{"張三", 20, true, 32.2} fmt.Println(slice) // [張三 20 true 32.2] }
4. map 的值實(shí)現(xiàn)空接口
func main() { // 空接口作為 map 值 var studentInfo = make(map[string]interface{}) studentInfo["name"] = "張三" studentInfo["age"] = 18 studentInfo["married"] = false fmt.Println(studentInfo) // [age:18 married:false name:張三] }
類(lèi)型斷言(從上往下轉(zhuǎn)換,接口類(lèi)型轉(zhuǎn)化為具體類(lèi)型)
- 一個(gè)接口的值(簡(jiǎn)稱(chēng)接口值)是由一個(gè)具體類(lèi)型和具體類(lèi)型的值兩部分組成的。
- 這兩部分分別稱(chēng)為接口的動(dòng)態(tài)類(lèi)型和動(dòng)態(tài)值。(一個(gè)空接口,可以是結(jié)構(gòu)體,指針,布爾各種類(lèi)型。它其實(shí)是動(dòng)態(tài)的,你傳遞什么都可以,這就叫做動(dòng)態(tài)類(lèi)型和動(dòng)態(tài)值)
- 如果我們想要判斷空接口中值的類(lèi)型,那么這個(gè)時(shí)候就可以使用類(lèi)型斷言
- 其語(yǔ)法格式: x.(T)
x : 表示類(lèi)型為 interface{}的變量
T : 表示斷言 x 可能是的類(lèi)型
斷言返回兩個(gè)值,一個(gè)是斷言是否轉(zhuǎn)化成果,一個(gè)是轉(zhuǎn)化結(jié)果,注意空接口類(lèi)型是空接口類(lèi)型。
var str interface{} str = "hello" str = str + "sss" //這樣寫(xiě)是會(huì)報(bào)錯(cuò)的,因?yàn)榭战涌陬?lèi)型不是字符串類(lèi)型,需要斷言轉(zhuǎn)化才可以
type test1 struct { name string age int } func main() { var t interface{} //未斷言前沒(méi)有結(jié)構(gòu)體的特征,需要斷言轉(zhuǎn)化為結(jié)構(gòu)體指針 t = &test1{ name: "hh", age: 12, } v, ok := t.(*test1) //這里其實(shí)就是做了一個(gè)類(lèi)型轉(zhuǎn)化,這里的類(lèi)型就變?yōu)閬?lái)結(jié)構(gòu)體指針類(lèi)型 if ok { fmt.Printf("類(lèi)型:%T 值:%#v\n", v, v) } else { fmt.Println("xxx") } } 類(lèi)型:*main.test1 值:&main.test1{name:"hh", age:12}
轉(zhuǎn)化為具體類(lèi)型之后,那么具體類(lèi)型的方法是都可以去調(diào)用的,空接口是不能訪問(wèn)屬性和方法的。轉(zhuǎn)化為具體的類(lèi)型之后就可以訪問(wèn)其屬性和方法。
值接收者和指針接收者(節(jié)省內(nèi)存)
1. 值接收者
當(dāng)方法作用于值類(lèi)型接收者時(shí),Go語(yǔ)言會(huì)在代碼運(yùn)行時(shí)將接收者的值復(fù)制一份。
在值類(lèi)型接收者的方法中可以獲取接收者的成員值,但修改操作只是針對(duì)副本,無(wú)法修改接收者變量本身。
type Usb interface { Start() Stop() } type Phone struct { Name string } func (p Phone) Start() { fmt.Println(p.Name, "開(kāi)始工作") } func (p Phone) Stop() { fmt.Println("phone 停止") } func main() { phone1 := Phone{ // 一:實(shí)例化值類(lèi)型 Name: "小米手機(jī)", } var p1 Usb = phone1 //phone1 實(shí)現(xiàn)了 Usb 接口 phone1 是 Phone 類(lèi)型 p1.Start() phone2 := &Phone{ // 二:實(shí)例化指針類(lèi)型 Name: "蘋(píng)果手機(jī)", } var p2 Usb = phone2 //phone2 實(shí)現(xiàn)了 Usb 接口 phone2 是 *Phone 類(lèi)型 p2.Start() //蘋(píng)果手機(jī) 開(kāi)始工作 }
2. 指針接收者
- 指針類(lèi)型的接收者由一個(gè)結(jié)構(gòu)體的指針組成
- 由于指針的特性,調(diào)用方法時(shí)修改接收者指針的任意成員變量,在方法結(jié)束后,修改都是有效的。
- 這種方式就十分接近于其他語(yǔ)言中面向?qū)ο笾械?this 或者 self 。
- 例如我們?yōu)?Person 添加一個(gè) SetAge 方法,來(lái)修改實(shí)例變量的年齡。
3. 指針類(lèi)型接收者
使用時(shí)機(jī)
注:并不是所有情況下都希望修改數(shù)據(jù)
- 需要修改接收者中的值
- 接收者是拷貝代價(jià)比較大的大對(duì)象
- 保證一致性,如果有某個(gè)方法使用了指針接收者,那么其他的方法也應(yīng)該使用指針接收者。
從使用場(chǎng)景上面來(lái)說(shuō),基本上都會(huì)使用指針,如果使用了第三方的包,第三方包的某些返回值它只是一個(gè)值類(lèi)型,所以第三方類(lèi)型返回什么類(lèi)型我們就使用什么類(lèi)型,針對(duì)第三方包。
到此這篇關(guān)于Golang接口的定義與空接口及斷言的使用示例的文章就介紹到這了,更多相關(guān)Golang接口的定義內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang使用singleflight解決并發(fā)重復(fù)請(qǐng)求
高并發(fā)的場(chǎng)景下,經(jīng)常會(huì)出現(xiàn)并發(fā)重復(fù)請(qǐng)求資源的情況,singleflight是golang內(nèi)置的一個(gè)包,這個(gè)包提供了對(duì)重復(fù)函數(shù)調(diào)用的抑制功能,所以下面我們就來(lái)看看如何使用它解決并發(fā)重復(fù)請(qǐng)求吧2023-08-08Hugo?Config模塊構(gòu)建實(shí)現(xiàn)源碼剖析
這篇文章主要為大家介紹了Hugo?Config模塊構(gòu)建實(shí)現(xiàn)源碼剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02通過(guò)Golang編寫(xiě)一個(gè)AES加密解密工具
這篇文章主要為大家詳細(xì)介紹了如何利用Golang制作一個(gè)AES加密解密工具,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-05-05golang實(shí)現(xiàn)對(duì)docker容器心跳監(jiān)控功能
這篇文章主要介紹了golang實(shí)現(xiàn)對(duì)docker容器心跳監(jiān)控功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09Centos下搭建golang環(huán)境及vim高亮Go關(guān)鍵字設(shè)置的方法
這篇文章先給大家詳細(xì)介紹了在Centos下搭建golang環(huán)境的步驟,大家按照下面的方法就可以自己搭建golang環(huán)境,搭建完成后又給大家介紹了vim高亮Go關(guān)鍵字設(shè)置的方法,文中通過(guò)示例代碼介紹的很詳細(xì),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-11-11Go到底能不能實(shí)現(xiàn)安全的雙檢鎖(推薦)
這篇文章主要介紹了Go到底能不能實(shí)現(xiàn)安全的雙檢鎖,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05基于go中fyne gui的通達(dá)信數(shù)據(jù)導(dǎo)出工具詳解
這篇文章主要介紹了基于go中fyne gui的通達(dá)信數(shù)據(jù)導(dǎo)出工具,這是一個(gè)用 Go 語(yǔ)言開(kāi)發(fā)的通達(dá)信數(shù)據(jù)導(dǎo)出工具,可以將通達(dá)信的本地?cái)?shù)據(jù)導(dǎo)出為多種格式,方便用戶(hù)進(jìn)行數(shù)據(jù)分析和處理,需要的朋友可以參考下2024-12-12