为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Go 中泛化函数包装?

如何在 Go 中泛化函数包装?

Go
阿晨1998 2022-06-27 16:17:39
我有以下界面: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)


查看完整回答
反对 回复 2022-06-27
?
缥缈止盈

TA贡献2041条经验 获得超4个赞

您在评论中提到参数类型有所不同。

一般来说,您可以这样做:

  • 在编译时,或

  • 在运行时。

运行时版本更易于编码和使用,并且非常灵活,但当然有一些运行时成本。也许您正试图避免这种情况(这很好,但会让人想起关于在优化之前进行测量的古老格言)。

编译时版本是您在示例中编写的。

我怎样才能重写它以便样板消失?

对于 Go 1,只有一种方法可以做到这一点:编写程序来编写程序。😀 这就是go generate全部。还有一篇关于它的Go 博客文章

在 Go 2 中,几乎肯定会有泛型,你实际上可以稍微玩一下。他们将是做你想做的事的方式。


查看完整回答
反对 回复 2022-06-27
  • 2 回答
  • 0 关注
  • 143 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号