How to constrain type to types with index?

Issue

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?

Solution

You can use a constraint with a union, however the only meaningful one you can have is:

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

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

And that’s all, for the time being. Why?

  1. The operations allowed on types with union constraint are only those allowed for all types in the constraint type set.

  2. To allow indexing, the types in the union must have equal key type and equal element type.

  3. 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.

  4. 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. Quite impractical, and prone to out-of-bounds issues (There’s a proposal to improve this).

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

Other than that, it seems there’s no other way to define a constraint that 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

Answered By – blackgreen

Answer Checked By – Marilyn (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.