一文帶你了解GO語言中方法的應(yīng)用
GO 中的方法是什么?
前面我們有分享到 GO 語言的函數(shù),他是一等公民,那么 GO 語言中的方法和函數(shù)有什么區(qū)別呢?
GO 語言中的方法實(shí)際上和函數(shù)是類似的,只不過在函數(shù)的基礎(chǔ)上多了一個(gè)參數(shù),這個(gè)參數(shù)在 GO 語言中被稱為 receiver 參數(shù)
例如我們可以這么來申明一個(gè)方法:
func (xx T/*T) helloworld(入?yún)?shù)列表) (返回值列表) { // 具體實(shí)現(xiàn) }
demo 中的 helloworld 方法就綁定到了 receiver T 類型上,這個(gè) helloworld 方法,我們可以通過使用 T 類型或者 *T 來進(jìn)行調(diào)用,例如:
var tt T tt.helloworld(入?yún)?shù)列表) var pt *T pt.helloworld(入?yún)?shù)列表)
看著還是挺簡單的對(duì)嗎?對(duì)于使用的時(shí)候我們需要注意這些問題:
- GO 語言中原生的類型,是不能作為上述的 receiver 的,例如 int,slice,map等等都是不行的,只能是我們自定義的類型
- 方法只能有一個(gè) receiver 參數(shù),只能綁定一個(gè),不能綁定多個(gè)
- receiver 參數(shù)類型本身不能是指針或者是接口類型,這里非常需要注意
如圖:receiver 參數(shù)類型本身不能是指針類型
如圖:receiver 參數(shù)類型本身不能是接口類型
對(duì)于方法,是綁定了一個(gè) receiver 類型的參數(shù),那么這個(gè)參數(shù)是不是很像 C++ 里面的入?yún)⒛兀?/p>
func helloworld(xx T/*T, 其他入?yún)? (返回值列表){ // 具體實(shí)現(xiàn) }
所以在 GO 語言里面,我們能夠明白一個(gè)方法所綁定類型的實(shí)例,實(shí)際上就是一個(gè)普通函數(shù)的第一個(gè)參數(shù)
就像這樣
func (t T) helloworld() == helloworld(t T) func (pt *T) helloworld() == helloworld(pt *T)
那么,**對(duì)于上述綁定的類型,有 T 也有 T ,如何去選擇呢?什么時(shí)候用 T 什么時(shí)候又用 T 呢?
此處 T 叫做值類型 , *T 叫做指針類型 ,選擇不同的類型,
- 如果選擇 T 類型,那么這是一個(gè)值傳遞類型的,在調(diào)用 helloworld 方法的時(shí)候,實(shí)際上就是傳了一個(gè) T 類型實(shí)例的副本,那么如果在 helloworld 方法中對(duì) t 做了一些變動(dòng),那么只會(huì)影響副本,對(duì)于原來的 T 類型實(shí)例,是不會(huì)有影響的
- 如果選擇了 *T 類型,那么這就是一個(gè)指針類型的,調(diào)用 helloworld 方法的時(shí)候,傳的就是類型 T 的實(shí)例地址,這個(gè)時(shí)候 helloworld 內(nèi)部如果對(duì) t 做了一些變動(dòng),都會(huì)體現(xiàn)到原來的 T 的實(shí)例上
這個(gè)理解方式實(shí)際上就和咱們普通函數(shù)中傳入的參數(shù)是一樣的,傳值和傳地址的區(qū)別
一個(gè)簡單的 demo ,再來加深一下:
- 定義個(gè) TT 類型的結(jié)構(gòu),成員有 Name
- 定義 Hello1 方法綁定 TT,定義 hello2 方法綁定 *TT
- 新建一個(gè) TT 類型的變量 t,分別去調(diào)用 hello1 和 hello2
- 新建一個(gè) *TT 類型的變量 pt,分別去調(diào)用 hello1 和 hello2
可以看到上述程序的結(jié)果如下:
name ==
name == hello2
name ==
name == hello2
從上述 demo 中就可以看出,實(shí)際上 GO 語言對(duì)于我們調(diào)用方法的時(shí)候是做了隱式轉(zhuǎn)換,無論是值類型的實(shí)例,還是指針類型的實(shí)例,都是可以去調(diào)用綁定了值類型的方法,也可以去調(diào)用綁定了指針類型的方法
只不過得到的結(jié)果,就要看具體方法是綁定的值類型,還是指針類型了
所以我們?nèi)绾稳ミx擇 receiver 的類型到此就很清楚了吧?
如果我們期望要去修改 receiver 類型的實(shí)例,那么就用指針類型,如果不期望修改,則使用值類型
當(dāng)然,如果我們是要考慮到性能,就要使用傳地址的方式較好
方法的集合
GO 里面雖然沒有類,沒有對(duì)象,沒有繼承,但是關(guān)于面向?qū)ο罄锩娴膬?nèi)容在 GO 里面完全可以使用組合的方式來進(jìn)行實(shí)現(xiàn)
所以對(duì)于GO 里面是如何組合的的基本知識(shí)我們要搞清楚,前提我們就先要弄明白方法的集合是如何玩的
在 GO 語言里面,我們?cè)诮o接口變量復(fù)制,使用結(jié)構(gòu)體嵌入或者接口嵌入,使用 類型別名的時(shí)候,都是會(huì)涉及到方法集合的,但是具體要看某一個(gè)實(shí)例包含哪些方法集合,我們就可以來演練一下
- 定義 ITT 接口,里面有 2 個(gè)方法 Hello1() , Hello2()
- 定義 TT 結(jié)構(gòu)體,實(shí)現(xiàn)上述接口,其中 Hello1() 綁定 TT , Hello2() 綁定 *TT
- 查看 nil 轉(zhuǎn)成 ITT 的方法集合,TT 的方法集合,*TT 的方法集合
type ITT interface{ Hello1() Hello2() } type TT struct{} func (t TT)Hello1(){} func (pt *TT)Hello2(){} // 打印方法集合 func GetMethodSet(i interface{}){ v := reflect.TypeOf(i) et := v.Elem() num := et.NumMethod() if num == 0 { fmt.Println(et, "methond num is 0" ) return } // 有方法集合 fmt.Println(et,"mthond set is :") for i:=0;i<num;i++{ fmt.Println("---",et.Method(i).Name) } } func main(){ var t TT var pt * TT // 先查看 nil 接口的方法集合 GetMethodSet((*ITT)(nil)) // 查看 TT 的方法集合 GetMethodSet(&t) // 查看 *TT 的方法集合 GetMethodSet(&pt) }
運(yùn)行結(jié)果如下:
可以查看到上述案例,綁定類型為 TT 的,方法集合只有 1 個(gè),綁定類型為 *TT 的方法集合有 2 個(gè),可以看得出來
**T 類型的方法集合是包含了 T 類型和 T 類型
T 類型的方法集合是包含了 T 類型
對(duì)于 GO 語言里面的組合,總的來說有三種,這個(gè)可以多多嘗試和寫 demo 練習(xí):
1.接口中嵌入接口
type ITT interface{ hello1() } type ITT2 interface{ hello2() } type ITT3 interface{ ITT ITT2 }
接口中嵌入接口,最終的接口方法個(gè)數(shù)是取和數(shù),此處我們要注意的地方就是方法名如果重復(fù),也是可以正常得到方法集合,具體使用接口中的方法,還是要看實(shí)例是如何實(shí)現(xiàn)的
2.結(jié)構(gòu)體中嵌入接口
type ITT interface{ hello1() hello2() } type ITT2 interface{ hello2() hello3() } type TT struct{ ITT ITT2 } // 此時(shí) TT 的方法集合就存在 hello2() 是沖突的,因此此處就需要 TT 去實(shí)現(xiàn)自己的 hello2() func (TT)hello2(){}
結(jié)構(gòu)體中嵌入接口,如果遇到同名的方法,GO 語言會(huì)優(yōu)先選擇結(jié)構(gòu)體自己實(shí)現(xiàn)的方法,如果結(jié)構(gòu)體自己未實(shí)現(xiàn),則會(huì)將接口中的同名方法提升到自己的結(jié)構(gòu)體中來
3.結(jié)構(gòu)體中嵌入結(jié)構(gòu)體
結(jié)構(gòu)體中嵌入結(jié)構(gòu)體,就要注意嵌入的結(jié)構(gòu)體是值類型的還是指針類型的,例如:
type TT struct{ TT1 *TT2 }
那么 TT 的方法集合是什么? *TT 的方法集合是什么?
TT 的方法集合就是按照正常值傳遞的來,等于 TT1 的方法集合 加上 *TT2 的方法集合
*TT 的方法集合按照地址傳遞的來,等于 *TT1的方法集合 加上 *TT2 的方法集合
那么類型別名的方法集合又是如何去查看的,有什么需要注意的地方嗎?
那么還是上述方法集合中的案例,我們分別給結(jié)構(gòu)體 TT 定一個(gè)別名,TTB,給接口類型 ITT 定義一個(gè) ITTB ,此時(shí)來查看別名的方法集合,與其原有類型的方法集合是否有差距
上述程序運(yùn)行結(jié)果如下:
main.ITT mthond set is :
--- Hello1
--- Hello2
main.ITT mthond set is :
--- Hello1
--- Hello2
main.TT mthond set is :
--- Hello1
main.TT mthond set is :
--- Hello1
*main.TT mthond set is :
--- Hello1
--- Hello2
*main.TT mthond set is :
--- Hello1
--- Hello2
通過打印結(jié)果,我們可以看到,類型別名的方法集合與原有類型的方法集合是一樣的,無論是結(jié)構(gòu)體類型還是接口類型
知道 receiver 能夠調(diào)用的方法集合有哪些, 那么在具體使用的時(shí)候,就避免出錯(cuò),避免誤解,對(duì)于后續(xù)的接口組合就會(huì)理解的更加明白和清晰了
到此這篇關(guān)于一文帶你了解GO語言中方法的應(yīng)用的文章就介紹到這了,更多相關(guān)go方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Golang設(shè)計(jì)模式之工廠方法模式講解和代碼示例
工廠方法是一種創(chuàng)建型設(shè)計(jì)模式, 解決了在不指定具體類的情況下創(chuàng)建產(chǎn)品對(duì)象的問題,本文將通過代碼示例詳細(xì)給大家介紹一下Golang工廠方法模式,感興趣的同學(xué)可以參考一下2023-06-06golang定時(shí)器Timer的用法和實(shí)現(xiàn)原理解析
這篇文章主要介紹了golang定時(shí)器Ticker,本文主要來看一下Timer的用法和實(shí)現(xiàn)原理,需要的朋友可以參考以下內(nèi)容2023-04-04以Golang為例詳解AST抽象語法樹的原理與實(shí)現(xiàn)
AST?使用樹狀結(jié)構(gòu)來表達(dá)編程語言的結(jié)構(gòu),樹中的每一個(gè)節(jié)點(diǎn)都表示源碼中的一個(gè)結(jié)構(gòu),本文將以GO語言為例,為大家介紹一下AST抽象語法樹的原理與實(shí)現(xiàn),希望對(duì)大家有所幫助2024-01-01GoFrame框架ORM原生方法對(duì)象操作開箱體驗(yàn)
這篇文章主要為大家介紹了GoFrame框架ORM原生方法對(duì)象操作的開箱體驗(yàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06GoFrame?gtree樹形結(jié)構(gòu)的使用技巧示例
這篇文章主要為大家介紹了GoFrame?gtree樹形結(jié)構(gòu)的使用技巧示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06再次探討go實(shí)現(xiàn)無限 buffer 的 channel方法
我們知道go語言內(nèi)置的channel緩沖大小是有上限的,那么我們自己如何實(shí)現(xiàn)一個(gè)無限 buffer 的 channel呢?今天通過本文給大家分享go實(shí)現(xiàn)無限 buffer 的 channel方法,感興趣的朋友一起看看吧2021-06-06