久久国产乱子伦精品免费M,亚洲一区二区三区91,欧美国产在线视频,国产精品视频久久

Go 語言開源項目使用的函數(shù)選項模式

01? 介紹

在閱讀 Go 語言開源項目的源碼時,我們可以發(fā)現(xiàn)有很多使用 “函數(shù)選項模式” ?的代碼,“函數(shù)選項模式” 是 Rob Pike 在 2014 年提出的一種模式,它使用 Go 語言的兩大特性,變長參數(shù)和閉包,可以使我們代碼更優(yōu)雅。

關(guān)于變長參數(shù)和閉包的介紹,需要的讀者朋友們可以查閱歷史文章,本文我們介紹 “函數(shù)選項模式” 的相關(guān)內(nèi)容。

02? 使用方式

在介紹“函數(shù)選項模式”的使用方式之前,我們先閱讀以下這段代碼。

type?User?struct?{
????Id?int
????Name?string
}

type?option?func(*User)

func?(u?*User)?Option(opts?...option)?{
????for?_,?opt?:=?range?opts?{
????????opt(u)
????}
}

func?WithId(id?int)?option?{
????return?func(u?*User)?{
????????u.Id?=?id
????}
}

func?WithName(name?string)?option?{
????return?func(u?*User)?{
????????u.Name?=?name
????}
}

func?main()?{
????u1?:=?&User{}
????u1.Option(WithId(1))
????fmt.Printf("%+v\n",?u1)
????
????u2?:=?&User{}
????u2.Option(WithId(1),?WithName("frank"))
????fmt.Printf("%+v\n",?u2)
}

輸出結(jié)果:

&{Id:1?Name:}
&{Id:1?Name:frank}

閱讀上面這段代碼,我們可以發(fā)現(xiàn),首先,我們定義一個名字是?option?的類型,它實際上是一個可以接收一個參數(shù)的函數(shù)。

然后,我們給?User?結(jié)構(gòu)體定義一個?Option?方法,該方法接收我們定義的?option?類型的變長參數(shù),方法體中使用?for-loop?執(zhí)行函數(shù)。

定義?WithId?函數(shù)和?WithName?函數(shù),設置?User?結(jié)構(gòu)體的字段?Id?和字段?Name,該函數(shù)通過返回閉包的形式實現(xiàn)。

以上使用方式是 “函數(shù)選項模式” 的一般使用方式。該使用方式可以解決大部分問題,但是,“函數(shù)選項模式” 還有進階使用方式,感興趣的讀者朋友們可以繼續(xù)閱讀 Part 03 的內(nèi)容。

03? 進階使用方式

所謂 “函數(shù)選項模式” 的進階使用方式,即有返回值的 “函數(shù)選項模式”,其中,返回值包含 golang 內(nèi)置類型和自定義?option?類型。

內(nèi)置類型的返回值

type?User?struct?{
????Id?int
????Name?string
}

type?option?func(*User)?interface{}

func?(u?*User)?Option(opts?...option)?(id?interface{})?{
????for?_,?opt?:=?range(opts)?{
????????id?=?opt(u)
????}
????return?id
}

func?WithId(id?int)?option?{
?return?func(u?*User)?interface{}?{
??prevId?:=?u.Id
??u.Id?=?id
??return?prevId
?}
}

func?main?()?{
????u1?:=?&User{Id:?1}
????id?:=?u1.Option(WithId(2))
????fmt.Println(id.(int))
????fmt.Printf("%+v\n",?u1)
}

輸出結(jié)果:

1
&{Id:2?Name:}

閱讀上面這段代碼,我們在定義?option?類型時,使用一個有返回值函數(shù)(此處使用的是空接口類型的返回值)。

WithId?函數(shù)的函數(shù)體中的代碼也稍作修改,閉包中使用?prevId?變量存儲結(jié)構(gòu)體?User?字段?Id?的原始數(shù)據(jù),并作為函數(shù)返回值。

細心的讀者朋友們可能已經(jīng)發(fā)現(xiàn),我們在?main?函數(shù)中顯式處理返回值,即:

...
id?:=?u1.Option(WithId(2))
fmt.Println(id.(int))
...

如果我們想要避免顯式處理返回值,可以使用返回自定義?option?類型的返回值的形式。

自定義 option 類型的返回值

type?User?struct?{
????Id?int
????Name?string
}

type?option?func(*User)?option

func?(u?*User)?Option(opts?...option)?(prev?option)?{
????for?_,?opt?:=?range?opts?{
????????prev?=?opt(u)
????}
????return?prev
}

func?WithId(id?int)?option?{
????return?func(u?*User)?option?{
????????prevId?:=?u.Id
????????u.Id?=?id
????????return?WithId(prevId)
????}
}

func?main?()?{
????u1?:=?&User{Id:?1}
????prev?:=?u1.Option(WithId(2))
????fmt.Printf("%+v\n",?u1)
????u1.Option(prev)
????fmt.Printf("%+v\n",?u1)
}

輸出結(jié)果:

&{Id:2?Name:}
&{Id:1?Name:}

閱讀上面這段代碼,我們在定義?option?類型時,通過把函數(shù)的返回值更改為?option?類型,我們就可以在?WithId?函數(shù)中,使用閉包處理?User?結(jié)構(gòu)體?Id?字段的原始值。

需要注意的是,?User?結(jié)構(gòu)體?Option?方法的返回值是??option?類型。

04? 使用示例

我們在了解完 “函數(shù)選項模式” 之后,使用該模式實現(xiàn)一個簡單示例。

type?User?struct?{
????Id?int
????Name?string
????Email?string
}

type?option?func(*User)

func?WithId(id?int)?option?{
????return?func(u?*User)?{
????????u.Id?=?id
????}
}

func?WithName(name?string)?option?{
????return?func(u?*User)?{
????????u.Name?=?name
????}
}

func?WithEmail(email?string)?option?{
?return?func(u?*User)?{
??u.Email?=?email
?}
}

func?NewUser(opts?...option)?*User?{
????const?(
????????defaultId?=?-1
????????defaultName?=?"guest"
????????defaultEmail?=?"undefined"
????)
????u?:=?&User{
????????Id:?defaultId,
????????Name:?defaultName,
????????Email:?defaultEmail,
????}
????
????for?_,?opt?:=?range?opts?{
????????opt(u)
????}
????return?u
}

func?main()?{
????u1?:=?NewUser(WithName("frank"),?WithId(1000000001))
????fmt.Printf("%+v\n",?u1)
????u2?:=?NewUser(WithEmail("gopher@88.com"))
????fmt.Printf("%+v\n",?u2)
????u3?:=?NewUser()
????fmt.Printf("%+v\n",?u3)
}

輸出結(jié)果:

&{Id:1000000001?Name:frank?Email:undefined}
&{Id:-1?Name:guest?Email:gopher@88.com}
&{Id:-1?Name:guest?Email:undefined}

閱讀上面這段代碼,我們使用 “函數(shù)選項模式” 實現(xiàn)構(gòu)造函數(shù)?NewUser,不僅可以自定義默認值(避免使用 Go 類型零值作為默認值),而且還可以使調(diào)用者靈活傳參(無需關(guān)心參數(shù)的順序和個數(shù))。

05? 總結(jié)

本文我們介紹怎么使用 Go 語言的 “函數(shù)選項模式”,通過閱讀完本文所有內(nèi)容,讀者朋友們應該已經(jīng)感受到該模式的優(yōu)點。

但是,該模式也有缺點,比如需要定義?WithXxx?函數(shù),增加了代碼量。

所以,我們可以根據(jù)實際使用場景決定是否選擇使用 “函數(shù)選項模式”。

原文鏈接:https://mp.weixin.qq.com/s/2jzg2PIK_esjTxSFMkp02A

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計算運維、SRE、Devops、網(wǎng)絡安全、云原生、Go、Python開發(fā)專業(yè)人才培訓機構(gòu)!

    1. 主站蜘蛛池模板: 独山县| 巧家县| 托里县| 鄂伦春自治旗| 济南市| 麻栗坡县| 息烽县| 永宁县| 陵川县| 建始县| 林甸县| 开鲁县| 四会市| 博客| 双江| 梨树县| 高唐县| 自治县| 三明市| 五莲县| 鱼台县| 德兴市| 禄丰县| 湖南省| 太白县| 镇雄县| 宜州市| 上虞市| 竹北市| 楚雄市| 蒙城县| 体育| 佛山市| 松溪县| 宝鸡市| 仁化县| 永昌县| 房山区| 健康| 紫云| 大关县|