How to constrain an interface to be only applicable for slices or maps

3 weeks ago 18
ARTICLE AD BOX

I've got a Matcher interface in Go that is implemented by quite a lot of underlying types.

I'd like to restrict the Matcher interface such that implementing types can only be a "collection", i.e. a slice or a map, for instance, so that I can call the built-in len() function on objects of these types.

package main import "fmt" type Slice interface { ~[]any } type Matcher interface { Slice // <- This doesn't seem to be allowed Match(s string) bool // Len() int // <- Want to avoid this, because the implementation is always the same } type Foo struct { Id string } type Bar struct { Id string } type FooSlice []Foo type BarSlice []Bar // implements Matcher func (fs FooSlice) Match(s string) bool { return true } func (bs BarSlice) Match(s string) bool { return false } func main() { matchers := []Matcher{ FooSlice{}, BarSlice{}, // ... } for _, s := range matchers { fmt.Println(len(s)) } }

However, the type constraint ~[]any does not seem to match my own slice types FooSlice and BarSlice, because I get:

./prog.go:31:16: cannot use type Matcher outside a type constraint: interface contains type constraints ./prog.go:32:3: cannot use FooSlice{} (value of slice type FooSlice) as Matcher value in array or slice literal: FooSlice does not implement Matcher (FooSlice missing in ~[]any) ./prog.go:33:3: cannot use BarSlice{} (value of slice type BarSlice) as Matcher value in array or slice literal: BarSlice does not implement Matcher (BarSlice missing in ~[]any) ./prog.go:37:19: invalid argument: s (variable of interface type Matcher) for built-in len

I know that I could just add a dedicated Len() int method to my Matcher interface - I added it commented out.

But the implementation would always be the same and therefore very repetitive.

Is there any solution to this problem? maybe using generics? A Wrapper struct? Embedding?

Thanks in advance.

Read Entire Article