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

我有以下界面:


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 传递给被包装函数的包装函数。我怎样才能重写它以便样板消失?


阿晨1998
浏览 144回答 2
2回答

慕容708150

您可以编写一个可变参数函数(请参阅函数类型),它将任意数量的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)

缥缈止盈

您在评论中提到参数类型有所不同。一般来说,您可以这样做:在编译时,或在运行时。运行时版本更易于编码和使用,并且非常灵活,但当然有一些运行时成本。也许您正试图避免这种情况(这很好,但会让人想起关于在优化之前进行测量的古老格言)。编译时版本是您在示例中编写的。我怎样才能重写它以便样板消失?对于 Go 1,只有一种方法可以做到这一点:编写程序来编写程序。😀 这就是go generate全部。还有一篇关于它的Go 博客文章。在 Go 2 中,几乎肯定会有泛型,你实际上可以稍微玩一下。他们将是做你想做的事的方式。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go