我有以下界面:type Selector interface { SelectOne(ctx context.Context, one A) (Result, error) SelectTwo(ctx context.Context, one A, two B) ([]Result, error) SelectThree(ctx context.Context, one A, two B, three C) ([]Result, error)}以及以下實現:type Database struct{}func (d Database) SelectOne(...) (...) {...}func (d Database) SelectTwo(...) (...) {...}func (d Database) SelectThree(...) (...) {...}然后,最重要的是,我想添加一個使用非常好的 github.com/hashicorp/golang-lru 庫的緩存層:type SelectorCache struct { db Database cacheOne *lru.Cache cacheTwo *lru.Cache}func (c SelectorCache) SelectOne(ctx context.Context, one A) (Result, error) { cached, ok := c.cacheOne.Get(makeKey(one)) if ok { casted, ok := cached.(Result) if ok { return casted, nil } } fetched, err := c.db.SelectOne(ctx, one) if err != nil { return Result{}, err } c.cache.Add(key, fetched) return fetched, nil}func (c SelectorCache) SelectTwo(ctx context.Context, one A, two B) ([]Result, error) { ... casted, ok := cached.([]Result) ... fetched, err := c.db.SelectTwo(ctx, one, two) ...}func () SelectThree(ctx context.Context, one A, two B, three C) ([]Result, error) { ... casted, ok := cached.([]Result) ... fetched, err := c.db.SelectThree(ctx, one, two, three) ...}如您所見,每種情況下的緩存層基本相同,唯一的區別在于底層功能。如果那是 Python,我可以輕松地創建一個將 *a, **kw 傳遞給被包裝函數的包裝函數。我怎樣才能重寫它以便樣板消失?
2 回答

慕容708150
TA貢獻1831條經驗 獲得超4個贊
您可以編寫一個可變參數函數(請參閱函數類型),它將任意數量的ints 作為參數(零或更多)并一次性處理它們。例如
func (d Database) Select(ctx context.Context, numbers ...int)
numbers您可以在for 循環中迭代range并執行您想要的操作。您的函數調用可以保持與以前相同。
fetched, err := c.db.Select(ctx, one)
fetched, err := c.db.Select(ctx, one, two)
fetched, err := c.db.Select(ctx, one, two, three)

縹緲止盈
TA貢獻2041條經驗 獲得超4個贊
您在評論中提到參數類型有所不同。
一般來說,您可以這樣做:
在編譯時,或
在運行時。
運行時版本更易于編碼和使用,并且非常靈活,但當然有一些運行時成本。也許您正試圖避免這種情況(這很好,但會讓人想起關于在優化之前進行測量的古老格言)。
編譯時版本是您在示例中編寫的。
我怎樣才能重寫它以便樣板消失?
對于 Go 1,只有一種方法可以做到這一點:編寫程序來編寫程序。?? 這就是go generate
全部。還有一篇關于它的Go 博客文章。
在 Go 2 中,幾乎肯定會有泛型,你實際上可以稍微玩一下。他們將是做你想做的事的方式。
- 2 回答
- 0 關注
- 131 瀏覽
添加回答
舉報
0/150
提交
取消