中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Golang必備技巧:接口型函數(shù)

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬Linux鏡像隨意使用

接口型函數(shù),指的是用函數(shù)實(shí)現(xiàn)接口,這樣在調(diào)用的時(shí)候就會(huì)非常簡(jiǎn)便,我稱這種函數(shù),為接口型函數(shù),這種方式使用于只有一個(gè)函數(shù)的接口。

我們以迭代一個(gè)map為例,演示這一技巧,這種方式有點(diǎn)類似于groovy中Map的each方法一樣,也是Gradle里each閉包。

原始接口實(shí)現(xiàn)

type Handler interface {
    Do(k, v interface{})
}
func Each(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            h.Do(k, v)
        }
    }
}

首先定義一個(gè)Handler接口,只有一個(gè)Do方法,接收k,v兩個(gè)參數(shù),這就是一個(gè)接口了,我們后面會(huì)實(shí)現(xiàn)他,具體做什么由我們的實(shí)現(xiàn)決定。

然后我們定義了一個(gè)Each函數(shù),這個(gè)函數(shù)的功能,就是迭代傳遞過來的map參數(shù),然后把map的每個(gè)key和value值傳遞給Handler的Do方法,去做具體的事情,可以是輸出,也可以是計(jì)算,具體由這個(gè)Handler的實(shí)現(xiàn)來決定,這也是面向接口編程。

現(xiàn)在我們就以新學(xué)期開學(xué),大家自我介紹為例,演示使用我們剛剛定義的Each方法和Handler接口。這里我們假設(shè)有三個(gè)學(xué)生,分別為:張三,李四和王五,他們每個(gè)人都要介紹自己的名字和年齡。

type welcome string

func (w welcome) Do(k, v interface{}) {
    fmt.Printf("%s,我叫%s,今年%d歲\n", w,k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["張三"] = 20
    persons["李四"] = 23
    persons["王五"] = 26

    var w welcome = "大家好"

    Each(persons, w)
}

以上實(shí)現(xiàn),我們定義了一個(gè)map來存儲(chǔ)學(xué)生們,map的key是學(xué)生的名字,value是該學(xué)生的年齡。 welcome 是我們新定義的類型,對(duì)應(yīng)基本類型string,該 welcome 實(shí)現(xiàn)了Handler接口,打印出自我介紹。

接口型函數(shù)出場(chǎng)

以上實(shí)現(xiàn),主要有兩點(diǎn)不太好:

  1. 因?yàn)楸仨氁獙?shí)現(xiàn)Handler接口,Do這個(gè)方法名不能修改,不能定義一個(gè)更有意義的名字

  2. 必須要新定義一個(gè)類型,才可以實(shí)現(xiàn)Handler接口,才能使用Each函數(shù)

首先我們先解決第一個(gè)問題,根據(jù)我們具體做的事情定義一個(gè)更有意義的方法名,比如例子中是自我介紹,那么使用selfInfo要比Do這個(gè)干巴巴的方法要好的多。

如果調(diào)用者改了方法名,那么就不能實(shí)現(xiàn)Handler接口,還要使用Each方法怎么辦?那就是由提供Each函數(shù)的負(fù)責(zé)提供Handler的實(shí)現(xiàn),我們添加代碼如下:

type HandlerFunc func(k, v interface{})
func (f HandlerFunc) Do(k, v interface{}){
    f(k,v)
}

以上代碼,我們定義了一個(gè)新的類型HandlerFunc,它是一個(gè)func(k, v interface{})類型,然后這個(gè)新的HandlerFunc實(shí)現(xiàn)了Handler接口,Do方法的實(shí)現(xiàn)是調(diào)用HandlerFunc本身,因?yàn)镠andlerFunc類型的變量就是一個(gè)方法。

現(xiàn)在我們使用這種方式實(shí)現(xiàn)同樣的效果。

type welcome string

func (w welcome) selfInfo(k, v interface{}) {
    fmt.Printf("%s,我叫%s,今年%d歲\n", w,k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["張三"] = 20
    persons["李四"] = 23
    persons["王五"] = 26

    var w welcome = "大家好"

    Each(persons, HandlerFunc(w.selfInfo))

}

還是差不多原來的實(shí)現(xiàn),只是把方法名Do改為selfInfo。 HandlerFunc(w.selfInfo) 不是方法的調(diào)用,而是轉(zhuǎn)型,因?yàn)閟elfInfo和HandlerFunc是同一種類型,所以可以強(qiáng)制轉(zhuǎn)型。轉(zhuǎn)型后,因?yàn)镠andlerFunc實(shí)現(xiàn)了Handler接口,所以我們就可以繼續(xù)使用原來的Each方法了。

進(jìn)一步重構(gòu)

現(xiàn)在解決了命名的問題,但是每次強(qiáng)制轉(zhuǎn)型不太好,我們繼續(xù)重構(gòu),可以采用新定義一個(gè)函數(shù)的方式,幫助調(diào)用者強(qiáng)制轉(zhuǎn)型。

func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
    Each(m,HandlerFunc(f))
}
type welcome string

func (w welcome) selfInfo(k, v interface{}) {
    fmt.Printf("%s,我叫%s,今年%d歲\n", w,k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["張三"] = 20
    persons["李四"] = 23
    persons["王五"] = 26

    var w welcome = "大家好"

    EachFunc(persons, w.selfInfo)

}

新增了一個(gè)EachFunc函數(shù),幫助調(diào)用者強(qiáng)制轉(zhuǎn)型,調(diào)用者就不用自己做了。

現(xiàn)在我們發(fā)現(xiàn)EachFunc函數(shù)接收的是一個(gè)func(k, v interface{})類型的函數(shù),沒有必要實(shí)現(xiàn)Handler接口了,所以我們新的類型可以去掉不用了。

func selfInfo(k, v interface{}) {
    fmt.Printf("大家好,我叫%s,今年%d歲\n", k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["張三"] = 20
    persons["李四"] = 23
    persons["王五"] = 26

    EachFunc(persons, selfInfo)

}

去掉了自定義類型 welcome 之后,整個(gè)代碼更簡(jiǎn)潔,可讀性更好。我們的方法含義都是:

  1. 讓這學(xué)生自我介紹

  2. 讓這些學(xué)生起立

  3. 讓這些學(xué)生早讀

  4. 讓這些學(xué)生…

都是這種默認(rèn),方法處理,更符合自然語言規(guī)則。

延伸

以上關(guān)于函數(shù)型接口就寫完了,如果我們仔細(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)我們例子中的Each和EachFunc這兩個(gè)函數(shù),靈活方便。

最后,附上完整的源代碼:

package main
import (
    "fmt"

)
type Handler interface {
    Do(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) Do(k, v interface{}) {
    f(k, v)
}
func Each(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
         for k, v := range m {
            h.Do(k, v)
        }
    }
}
func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
    Each(m, HandlerFunc(f))
}
func selfInfo(k, v interface{}) {
    fmt.Printf("大家好,我叫%s,今年%d歲\n", k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["張三"] = 20
    persons["李四"] = 23
    persons["王五"] = 26

    EachFunc(persons, selfInfo)

}

 

來自:http://mp.weixin.qq.com/s/ly2aPcmfc__1lliHP4EUUQ

 

標(biāo)簽: 代碼 轉(zhuǎn)型

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:作為 Android 開發(fā)者必須了解的 Gradle 知識(shí)

下一篇:Python 高級(jí)編程:完全理解生成器