我有以下界面: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 关注
- 143 浏览
添加回答
举报
0/150
提交
取消