我有以下界面:
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传递给包装函数的包装函数。我该如何重写,以使样板消失?
最佳答案
您在注释中提到参数类型有所不同。
通常,您可以执行以下操作:
编译时为
运行时版本更易于编码和使用,并且非常灵活,但是当然会花费一些运行时成本。也许您正在尝试避免这种情况(很好,但是请记住关于在优化之前进行测量的古老说法)。
编译时版本就是您在示例中编写的版本。
How can I rewrite that so the boilerplate gets gone?
对于Go 1,只有一种方法可以做到:编写程序来编写程序。 oji这就是
go generate
的全部含义。也有一个Go blog post。在Go 2中,几乎可以肯定会有generics,您实际上可以稍微玩一下。它们将成为您想要做的方式。
关于function - 如何在Go中概括函数包装?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63776909/