Explain the "pointer method" constraint pattern (PT interface{ *T; M() }). Why is it needed?
Question 127HardGo 1.22 to 1.25
Problem: you want to create values of type T inside a generic function and call a method that has a pointer receiver, such as UnmarshalText or Set. T itself does not have that method in its method set, and *T does, but there is no way to say "*T has method M" directly. The fix is a second type parameter that is constrained to be *T and to have the method.
type Setter[T any] interface {
*T // PT must be exactly *T
Set(string) error // ...and have Set
}
func ParseAll[T any, PT Setter[T]](in []string) ([]T, error) {
out := make([]T, len(in))
for i, s := range in {
p := PT(&out[i]) // convert *T to PT
if err := p.Set(s); err != nil {
return nil, err
}
}
return out, nil
}
type Level int
func (l *Level) Set(s string) error {
n, err := strconv.Atoi(s)
*l = Level(n)
return err
}
// PT inferred as *Level via constraint type inference
levels, err := ParseAll[Level]([]string{"1", "2", "3"})
If you wrote func ParseAll[T Setter](...) instead, callers would pass *Level. var zero T would then be a nil pointer, and calling Set would panic. Interviewers are checking that you know the relationship between method sets and pointers, and the nil-pointer trap.
More on Generics
- Q125How do you write methods on a generic type? What is wrong with
func (s Stack[int]) Sum() int? - Q126Name the restrictions around type parameters: embedding, type declarations, and method sets.
- Q128What are self-referential (recursive) constraints and generic interfaces? Give an example.
- Q129Why does
slices.Clonehave the signaturefunc Clone[S ~[]E, E any](s S) Sinstead offunc Clone[E any](s []E) []E? - Q130How does the Go compiler implement generics (GC shape stenciling with dictionaries)? What are the performance implications?
- Q131When should you NOT use generics?