Home > OS >  How to constrain type to types with index?
How to constrain type to types with index?

Time:02-26

I decided to dive into Go since 1.18 introduced generics. I want to implement an algorithm that only accepts sequential types — arrays, slice, maps, strings, but I'm not able to crack how.

Is there a method that can be targeted involving indexability?

CodePudding user response:

You can use a constraint with a union. However the operations allowed on types with union constraint are only those allowed for all types in the constraint type set.

To allow indexing, the types in the union must have equal key type, — used for indexing, and equal element type — resulting from the index expression.

So the union would look like:

type Indexable interface {
    ~[]byte | ~string
}

func GetAt[T Indexable](v T, i int) byte {
    return v[i]
}

And that's about all you can get. The type parameter proposal suggests that map[int]T could be used in a union with []T — given that slices must be indexed with int, however this has been disallowed.

Now, for arrays, the length is part of the type, so a union would have to specify all possible lengths you want to handle, e.g. [1]T | [2]T etc. A bit impractical, and prone to out-of-bounds issues (There's a proposal to improve this).

So the only meaningful union that supports indexing appears to be []byte | string (possibly with approximation ~). Since byte is an alias of uint8, you can also instantiate with []uint8.

Other than that, it seems there's no other way to constrain a type parameter so that it supports indexing on all possible indexable types.

NOTE that []byte | string supports indexing but not range, because ranging over a string yields rune, not byte.

Playground: https://gotipplay.golang.org/p/uatvtMo_mrZ

  • Related