Golang接口型函數(shù)使用小結(jié)
什么是接口型函數(shù)?顧名思義接口函數(shù)指的是用函數(shù)實(shí)現(xiàn)接口,這樣在調(diào)用的時(shí)候就會(huì)非常簡(jiǎn)便,這種方式適用于只有一個(gè)函數(shù)的接口。
這里以迭代一個(gè)map為例,演示這一實(shí)現(xiàn)的技巧。
常規(guī)接口實(shí)現(xiàn)
defer語(yǔ)句用于延遲函數(shù)調(diào)用,每次會(huì)把一個(gè)函數(shù)壓入棧中,函數(shù)返回前再把延遲的函數(shù)取出并執(zhí)行。延遲函數(shù)可以有參數(shù):
- 延遲函數(shù)的參數(shù)在defer語(yǔ)句出現(xiàn)時(shí)就已確定下來(lái)(傳值的就是當(dāng)前值);
- 延遲函數(shù)執(zhí)行按后進(jìn)先出順序執(zhí)行;
- 延遲函數(shù)可操作主函數(shù)的具名返回值(修改返回值);
type Handler interface {
DoFunc(k, v interface{})
}
func DoEach(m map[interface{}]interface{}, h Handler) {
if m != nil && len(m) > 0 {
for k, v := range m {
h.DoFunc(k, v)
}
}
}這里我們定義了一個(gè)Handler接口,只有一個(gè)DoFunc方法,接收k,v兩個(gè)參數(shù),這就是一個(gè)接口了,我們后面會(huì)實(shí)現(xiàn)他,具體做什么由我們的實(shí)現(xiàn)決定。
然后我們定義了一個(gè)DoEach函數(shù),該函數(shù)的功能就是迭代傳遞過(guò)來(lái)的map參數(shù),然后把map的每個(gè)key和value值傳遞給Handler的DoFunc方法,
具體由這個(gè)Handler的實(shí)現(xiàn)來(lái)決定,這也是面向接口編程。
說(shuō)得再多不如來(lái)點(diǎn)實(shí)際的例子:用我們剛剛定義的DoEach方法和Handler接口。
package main
import "fmt"
type Handler interface {
DoFunc(k, v interface{})
}
func DoEach(m map[interface{}]interface{}, h Handler) {
if m != nil && len(m) > 0 {
for k, v := range m {
h.DoFunc(k, v)
}
}
}
type greet string
func ( g greet) DoFunc(k, v interface{}) {
fmt.Printf("%s,在下%s,我的必殺技是%s\n", g, k, v)
}
func main() {
persons := make(map[interface{}]interface{})
persons["喬峰"] = "龍爪手"
persons["鳩摩智"] = "小無(wú)相功"
persons["慕容復(fù)"] = "斗轉(zhuǎn)星移"
var g greet = "諸位英雄"
DoEach(persons, g)
}輸出:
諸位英雄,在下喬峰,我的必殺技是龍爪手
諸位英雄,在下鳩摩智,我的必殺技是小無(wú)相功
諸位英雄,在下慕容復(fù),我的必殺技是斗轉(zhuǎn)星移
以上實(shí)現(xiàn),我們定義了一個(gè)map來(lái)存儲(chǔ)幾位大佬,map的key是大佬的名字,value是該大佬的絕技。greet是我們新定義的類型,
其對(duì)應(yīng)基本類型string,該greet實(shí)現(xiàn)了Handler接口,打印出自我介紹的信息。
接口型函數(shù)出場(chǎng)
關(guān)于上面的實(shí)現(xiàn),我們可以發(fā)現(xiàn),有兩點(diǎn)不太好:
- 因?yàn)楸仨氁獙?shí)現(xiàn)Handler接口,DoFunc這個(gè)方法名不能修改,不能定義一個(gè)更有意義的名字
- 必須要新定義一個(gè)類型,才可以實(shí)現(xiàn)Handler接口,才能使用DoEach函數(shù)
首先我們先解決第一個(gè)問(wèn)題,根據(jù)我們具體做的事情定義一個(gè)更有意義的方法名,比如例子中是自我介紹,
那么我們使用selfintroduction是不是要比DoFunc這個(gè)語(yǔ)義的方法要好呢。
如果調(diào)用者改了方法名,那么就不能實(shí)現(xiàn)Handler接口,還要使用DoEach方法怎么辦?那就是由提供DoEach函數(shù)的負(fù)責(zé)提供Handler的實(shí)現(xiàn),
我們改造下代碼如下:
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
f(k, v)
}上面代碼我們定義了一個(gè)新的類型HandlerFunc,它是一個(gè)func(k, v interface{})類型,然后這個(gè)新的HandlerFunc實(shí)現(xiàn)了Handler接口(原始實(shí)現(xiàn)方式中的
type Handler interface { DoFunc(k, v interface{}) }),DoFunc方法的實(shí)現(xiàn)是調(diào)用HandlerFunc本身,因?yàn)镠andlerFunc類型的變量就是一個(gè)方法?,F(xiàn)在我們使用這種方式實(shí)現(xiàn)同樣的效果。
完整代碼如下:
package main
import "fmt"
type Handler interface {
DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
f(k, v)
}
type greet string
func (g greet) selfintroduction(k, v interface{}) {
fmt.Printf("%s,在下%s,我的必殺技是%s\n", g, k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
if m != nil && len(m) > 0 {
for k, v := range m {
h.DoFunc(k, v)
}
}
}
func main() {
persons := make(map[interface{}]interface{})
persons["喬峰"] = "龍爪手"
persons["鳩摩智"] = "小無(wú)相功"
persons["慕容復(fù)"] = "斗轉(zhuǎn)星移"
var g greet = "諸位英雄"
DoEach(persons, HandlerFunc(g.selfintroduction))
} 輸出:
諸位英雄,在下喬峰,我的必殺技是龍爪手
諸位英雄,在下鳩摩智,我的必殺技是小無(wú)相功
諸位英雄,在下慕容復(fù),我的必殺技是斗轉(zhuǎn)星移
還是差不多原來(lái)的實(shí)現(xiàn),只是把原接口方法名DoFunc改為selfintroduction。HandlerFunc(g.selfintroduction)不是方法的調(diào)用,而是轉(zhuǎn)型,因?yàn)閟elfintroduction和HandlerFunc是同一種類型,
所以可以強(qiáng)制轉(zhuǎn)型。轉(zhuǎn)型后,因?yàn)镠andlerFunc實(shí)現(xiàn)了Handler接口,所以我們就可以繼續(xù)使用原來(lái)的DoEach方法了。
進(jìn)一步改造
現(xiàn)在解決了命名的問(wèn)題,但是每次強(qiáng)制轉(zhuǎn)型是不是不太好?我們繼續(xù)重構(gòu)下,可以采用新定義一個(gè)函數(shù)的方式,幫助調(diào)用者強(qiáng)制轉(zhuǎn)型。
完整代碼如下:
package main
import "fmt"
type Handler interface {
DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
f(k, v)
}
type greet string
func (g greet) selfintroduction(k, v interface{}) {
fmt.Printf("%s,在下%s,我的必殺技是%s\n", g, k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
if m != nil && len(m) > 0 {
for k, v := range m {
h.DoFunc(k, v)
}
}
}
func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
DoEach(m, HandlerFunc(f))
}
func main() {
persons := make(map[interface{}]interface{})
persons["喬峰"] = "龍爪手"
persons["鳩摩智"] = "小無(wú)相功"
persons["慕容復(fù)"] = "斗轉(zhuǎn)星移"
var g greet = "諸位英雄"
EachFunc(persons, g.selfintroduction)
} 上面我們新增了一個(gè)EachFunc函數(shù),幫助調(diào)用者強(qiáng)制轉(zhuǎn)型,調(diào)用者就不用自己做了。
現(xiàn)在我們發(fā)現(xiàn)EachFunc函數(shù)接收的是一個(gè)func(k, v interface{})類型的函數(shù),沒(méi)有必要實(shí)現(xiàn)原Handler接口了,所以我們新的類型可以去掉不用了。
去掉了自定義類型greet之后,整個(gè)代碼更簡(jiǎn)潔,可讀性是不是更好點(diǎn)?簡(jiǎn)潔干凈的完整代碼如下:
package main
import "fmt"
type Handler interface {
DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
f(k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
if m != nil && len(m) > 0 {
for k, v := range m {
h.DoFunc(k, v)
}
}
}
func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
DoEach(m, HandlerFunc(f))
}
func selfintroduction(k, v interface{}) {
fmt.Printf("諸位英雄,在下%s,我的必殺技是%s\n", k, v)
}
func main() {
persons := make(map[interface{}]interface{})
persons["喬峰"] = "龍爪手"
persons["鳩摩智"] = "小無(wú)相功"
persons["慕容復(fù)"] = "斗轉(zhuǎn)星移"
EachFunc(persons, selfintroduction)
}以上關(guān)于函數(shù)型接口就寫(xiě)完了,如果大家仔細(xì)留意,發(fā)現(xiàn)和我們自己平時(shí)使用的http.Handle方法非常類似,其實(shí)接口http.Handler就是這么實(shí)現(xiàn)的。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}這是一種非常好的技巧,提供兩種函數(shù),既可以以接口的方式使用,也可以以方法的方式,
對(duì)應(yīng)我們例子中的DoEach和EachFunc這兩個(gè)函數(shù),靈活方便,也更符合自然語(yǔ)言規(guī)則吧。
無(wú)論從事什么行業(yè),只要做好兩件事就夠了,一個(gè)是你的專業(yè)、一個(gè)是你的人品,專業(yè)決定了你的存在,人品決定了你的人脈,剩下的就是堅(jiān)持,用善良專業(yè)和真誠(chéng)贏取更多的信任。
到此這篇關(guān)于Golang接口型函數(shù)使用技巧的文章就介紹到這了,更多相關(guān)Golang接口使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go在GoLand中引用github.com中的第三方包具體步驟
這篇文章主要給大家介紹了關(guān)于Go在GoLand中引用github.com中第三方包的具體步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Go具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01
go進(jìn)行http請(qǐng)求偶發(fā)EOF問(wèn)題分析
go使用連接池進(jìn)行http請(qǐng)求,一般都能請(qǐng)求成功,但偶然會(huì)出現(xiàn)請(qǐng)求失敗返回EOF錯(cuò)誤的情況,本文主要來(lái)帶大家分析一下為什么會(huì)出現(xiàn)這樣的問(wèn)題并提供解決方法,需要的可以參考下2025-01-01
Go語(yǔ)言中的Slice學(xué)習(xí)總結(jié)
這篇文章主要介紹了Go語(yǔ)言中的Slice學(xué)習(xí)總結(jié),本文講解了Slice的定義、Slice的長(zhǎng)度和容量、Slice是引用類型、Slice引用傳遞發(fā)生“意外”等內(nèi)容,需要的朋友可以參考下2014-11-11
Go語(yǔ)言中的流程控制結(jié)構(gòu)和函數(shù)詳解
這篇文章主要介紹了Go語(yǔ)言中的流程控制結(jié)構(gòu)和函數(shù)詳解,本文詳細(xì)講解了if、goto、for、switch等控制語(yǔ)句,同時(shí)對(duì)函數(shù)相關(guān)知識(shí)做了講解,需要的朋友可以參考下2014-10-10
golang自帶的死鎖檢測(cè)并非銀彈的問(wèn)題小結(jié)
Go語(yǔ)言自帶的死鎖檢測(cè)機(jī)制并不萬(wàn)能,它只對(duì)用戶創(chuàng)建的協(xié)程進(jìn)行檢測(cè),并且在特定條件下可能會(huì)“失靈”,死鎖檢測(cè)的觸發(fā)時(shí)機(jī)和檢測(cè)內(nèi)容也有限制,因此不能完全避免死鎖問(wèn)題,為了預(yù)防死鎖,應(yīng)該在編寫(xiě)代碼時(shí)提前進(jìn)行設(shè)計(jì)和測(cè)試,感興趣的朋友跟隨小編一起看看吧2025-01-01

