Go

How do you write a generic function that needs to call a pointer-receiver method on T? (the PT interface{ *T; M() } pattern)

Question 109HardGo 1.22 to 1.25
type Setter interface{ Set(string) }

type Settable struct{ v string }
func (s *Settable) Set(v string) { s.v = v }

// Attempt 1: T Setter
func Bad[T Setter](xs []string) []T {
    out := make([]T, len(xs))
    for i, x := range xs {
        out[i].Set(x) // T must be *Settable, so out[i] is a nil pointer: panic
    }
    return out
}
// Bad[Settable](...)   // compile error: Settable does not satisfy Setter
//                      // (method Set has pointer receiver)

// Fix: a second type parameter constrained to "pointer to T that has Set"
type PtrSetter[T any] interface {
    *T
    Setter
}

func FromStrings[T any, PT PtrSetter[T]](xs []string) []T {
    out := make([]T, len(xs))
    for i, x := range xs {
        PT(&out[i]).Set(x) // convert *T to PT, then call the method
    }
    return out
}

fmt.Println(FromStrings[Settable]([]string{"a", "b"})) // [{a} {b}]

The problem is that a constraint describes T's method set, but the method is on *T. If you instantiate with the pointer type, make([]T, n) gives you nil pointers and new(T) gives you a **Settable. The fix adds a type parameter PT whose type set is exactly *T and which also requires Set. Because PT's core type is *T, you can convert &out[i] to it.

The caller writes only FromStrings[Settable]: constraint type inference derives PT = *Settable from the *T element. This pattern is common in ORMs, decoders and protobuf helpers (for example, proto.Message constraints of the form interface{ *T; proto.Message }).

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions