Usage of ~[]T

Let’s consider these functions:

func Clone1[S ~[]E, E any](s S) S {...}
func Clone2[E any](s []E) []E {...}
 
func Reverse1[S ~[]E, E any](s S) {...}
func Reverse2[E any](s []E) {...}

Clone

In the case of Clone functions we should use Clone1 because Clone2 doesn’t allow to use named slice types:

type MySlice []string
func (s MySlice) String() string { return strings.Join(s, "+") }

If we use Clone2 we get a compiler error:

func PrintSorted(ms MySlice) string {
    c := Clone2(ms)
    slices.Sort(c)
    return c.String() // FAILS TO COMPILE
}

The Go assignment rules allow us to pass a value of type MySlice to a parameter of type []string, so calling Clone2 is fine. But Clone2 will return a value of type []string, not a value of type MySlice. The type []string doesn’t have a String method, so the compiler reports an error

Reverse

In the case of Reverse functions we should also prefer Reverse1

Reverse doesn’t return the slice, so it works even with named slice types such as MySlice

However, there is still a case where it makes a difference: when instantiating Reverse1 you can only get a func([]string), not a func(MySlice). This matters when passing them to higher level functions:

func Apply(ms MySlice) {
	apply(ms, Reverse1) // Compiles
	apply(ms, Reverse2) // Does not compile
	apply[[]string](ms,Reverse2) // Compiles
}
 
func apply[T any](v T, f func(T)) {
	f(v)
}

We have a compile error for the second call to apply: type func[E any](s []E) of Reverse2 does not match inferred type func(MySlice) for func(T)

To solve this issue we must provide the type explicitly: apply[[]string](ms,Reverse2)

References