I have the following interface:
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) } and the following implementations:
type Database struct{} func (d Database) SelectOne(...) (...) {...} func (d Database) SelectTwo(...) (...) {...} func (d Database) SelectThree(...) (...) {...} Then, on top of that, I want to add a cache layer that uses the very nice github.com/hashicorp/golang-lru library:
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) ... } As you see, the cache layer is basically the same for each case with the only difference being in the underlying function. If that was Python, I could easily create a wrapper function that passes *a, **kw to the wrapped function. How can I rewrite that so the boilerplate gets gone?