How do constraint interfaces in generics differ from ordinary interfaces?
Question 104HardGo 1.22 to 1.25
Since Go 1.18, an interface defines a type set. A basic interface (methods only) can be used both as a value type and as a constraint. An interface that contains type elements (int | string, ~float64) or embeds comparable is a constraint-only interface. You cannot declare a variable, field or parameter of that interface type.
type Number interface {
~int | ~int64 | ~float64 // ~ includes types whose underlying type is int, etc.
}
func Sum[T Number](xs []T) T {
var s T
for _, x := range xs {
s += x // allowed: every type in the set supports +
}
return s
}
type Celsius float64
fmt.Println(Sum([]Celsius{1.5, 2.5})) // 4 (works thanks to ~float64)
// var n Number // error: cannot use type Number outside a type constraint
// Mixing methods and type elements
type StringableInt interface {
~int
String() string
}
// Type switch on a type parameter requires converting to any first
func Kind[T any](v T) string {
switch any(v).(type) {
case int:
return "int"
default:
return "other"
}
}
Key differences:
- A call through a type parameter is resolved per GC shape. There is no boxing, but methods are still called indirectly through a dictionary.
- Operators such as
+and<are allowed only when every type in the set supports them. comparableis satisfied by interface types since Go 1.20, so==can panic.- A value of type-parameter type cannot be type-asserted directly. Convert it to
anyfirst.
More on Interfaces, Methods & Embedding
- Q102On which types can you declare methods? Can you add a method to
int,time.Time, a pointer type, or an interface? - Q103How does the "optional interface" (interface upgrade) pattern work? Give a stdlib example and its pitfall.
- Q105Do methods carry over with
type B Avstype B = Avs embedding? What does this mean forsync.Mutex? - Q106How does
http.HandlerFuncwork? Explain the function-type adapter pattern. - Q107What happens when you call a value-receiver method through an interface that holds a nil pointer?
- Q108Can you modify a struct stored inside an interface? What does this print?