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