91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

go中函數選項模式

發布時間:2020-06-27 19:49:47 來源:網絡 閱讀:768 作者:wx5cf612fe3a728 欄目:編程語言

作為golang開發人員,您將遇到的許多問題之一是嘗試將函數的參數設置為可選。有時候使用默認設置,但有時候需要提供自定義設置。

在許多語言中,這很容易;在c系列語言中,您可以使用不同數量的參數提供相同函數的多個版本,在php這樣的語言中,您可以為參數提供默認值,并在調用方法時忽略它們。但在golang您不能做到這兩點。那么在go中該如何實現呢?

我們來看一個例子吧,假設我們有一個名為StuffClient的服務,它可以執行一些操作并具有兩個配置選項(超時和重試):

type StuffClient interface {
    DoStuff() error
}

type stuffClient struct {
    conn Connection
    timeout int
    retries int
}

該結構是私有的,所以我們應該為它提供某種構造函數

func NewStuffClient(conn Connection, timeout, retries int) StuffClient {

    return &stuffClient {
        conn: conn,
        timeout: timeout,
        retries: retries,
    }
}

但現在我們總是要在每次調用NewStuffClient時提供超時和重試。大多數時候我們只想使用默認值。我們無法使用不同數量的參數定義多個版本的NewStuffClient, 否則我們將得到一個編譯錯誤。
一種選擇時創建另一個具有不同名稱的構造函數,例如

func NewStuffClient (conn Connection) StuffClient {

    return &stuffClient {
        conn: conn,
        timeout: DefaultTimeout,
        retries: DefaultRetries,
    }
}

func NewStuffClienWithOptions(conn Connection, timeout, retries int) StuffClient {

    return &stuffClient {
        conn: conn,
        timeout: timeout,
        retries: retries,
    }
}

我們還可以做的更好,將所有選項放到配置對象中

type StuffClientOptions struct {
    Retries int
    Timeout int
}

func NewStuffClient(conn Connection, options StuffClientOptions) StuffClient {
    return &stuffClient {
        conn: conn,
        timeout: options.Timeout,
        retries: options.Retries,
    }
}

但那也不是很好,現在我們必須這個結構并傳入它,即使我們不想指定任何選項,我們也沒有自動填寫的默認值,除非我們在代碼中添加了一堆檢查或者我們可以傳入一個DefaultSuffClientOptions變量(但這可能會導致在一個地方被修改,影響別的地方)

那么解決方案是什么?解決這個難題的最好方法就是使用函數選項模式,利用go閉包的方便支持,讓我們保留上面定義的 StuffClientOptions,但我們會添加一些東西:

type StuffClientOption func(*StuffClientOptions)
type StuffClientOptions struct {
    Retries int
    Timeout int
}

func WithRetries(r int) StuffClientOption {
    return func(o *StuffClientOptions) {
        o.retries = r
    }
}

func WithTimeout(t int) StuffClientOption {
    return func(o *StuffClientOptions) {
        o.timeout = t
    }
}

var defaultStuffClientOptions = StuffClientOptions {
    Retries: 3,
    Timeout: 2,
}

func NewStuffClient(conn Connection, opts ...StuffClientOption) StuffClient {
    options := defaultStuffClientOptions
    for _, o := range opts {
        o(&options)
    }

    return &stuffClient{
        conn: conn,
        timeout: options.Timeout,
        retries: options.Retries,
    }
}

現在看起來已經非常好用了。關于它的好處是我們可以隨時添加新選項,只需要對代碼進行少量的更改。

var defaultStuffClientOptions = StuffClientOptions{
    Retries: 3,
    Timeout: 2,
}
type StuffClientOption func(*StuffClientOptions)
type StuffClientOptions struct {
    Retries int //number of times to retry the request before giving up
    Timeout int //connection timeout in seconds
}
func WithRetries(r int) StuffClientOption {
    return func(o *StuffClientOptions) {
        o.Retries = r
    }
}
func WithTimeout(t int) StuffClientOption {
    return func(o *StuffClientOptions) {
        o.Timeout = t
    }
}
type StuffClient interface {
    DoStuff() error
}
type stuffClient struct {
    conn    Connection
    timeout int
    retries int
}
type Connection struct {}
func NewStuffClient(conn Connection, opts ...StuffClientOption) StuffClient {
    options := defaultStuffClientOptions
    for _, o := range opts {
        o(&options)
    }
        return &stuffClient{
            conn:    conn,
            timeout: options.Timeout,
            retries: options.Retries,
        }
}
func (c stuffClient) DoStuff() error {
    return nil
}

我們也可以通過刪除 StuffClientOptions 結構并將選項直接應用于我們的StuffClient, 可以進一步簡化這一過程

var defaultStuffClient = stuffClient{
    retries: 3,
    timeout: 2,
}
type StuffClientOption func(*stuffClient)
func WithRetries(r int) StuffClientOption {
    return func(o *stuffClient) {
        o.retries = r
    }
}
func WithTimeout(t int) StuffClientOption {
    return func(o *stuffClient) {
        o.timeout = t
    }
}
type StuffClient interface {
    DoStuff() error
}
type stuffClient struct {
    conn    Connection
    timeout int
    retries int
}
type Connection struct{}
func NewStuffClient(conn Connection, opts ...StuffClientOption) StuffClient {
    client := defaultStuffClient
    for _, o := range opts {
        o(&client)
    }

    client.conn = conn
    return client
}
func (c stuffClient) DoStuff() error {
    return nil
}

在我們的示例中,只是將配置直接應用于結構,在中間有一個額外的配置結構是沒有意義的,但請注意,在許多情況下,您可能仍希望使用上一個示例中的config結構,例如:如果你的構造函數使用配置選項來執行某些操作但并沒有將它們存儲到結構中,或者他們被傳遞到其他地方。config結構變量是更通用的實現。

使用步驟

  • 定義選項config結構體
    type options struct{
        timeout time.Duration
    }
  • 定義默認config結構體變量
    var defaultOptions = options{}
  • 定義配置選項函數
    type option func(*options)
    func WithTimeout(t time.Duration) options {
        return func(o *options) {
            o.timeout = t
        }
    }
  • 應用函數選項配置
    func Do(opts ...option) {
        d := defaultOptions
        for _, o := range opts {
            o(&d)
        }
    }

原文鏈接:

https://halls-of-valhalla.org/beta/articles/functional-options-pattern-in-go,54/

相關參考連接

Dave Cheney: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
Rob Pike: https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

昭苏县| 攀枝花市| 山东| 星子县| 湖北省| 东乡县| 乐安县| 武山县| 耒阳市| 武川县| 遂溪县| 和顺县| 郯城县| 和政县| 阿拉善左旗| 扎兰屯市| 上林县| 乐亭县| 涿鹿县| 无锡市| 蓝山县| 苍溪县| 葵青区| 阿克陶县| 民丰县| 台北市| 乃东县| 九龙城区| 库车县| 铜川市| 兴国县| 台前县| 平湖市| 青铜峡市| 金川县| 平江县| 绥中县| 自治县| 本溪市| 绵竹市| 台中县|