Description
Context
Type inference is a powerful feature where Go can infer generic types based on usage. In the following example, the RPC(Hello)
function is able to infer types based on the function signature.
func RPC[In, Out any, Fn Func[In, Out]](fn Fn) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var in In
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
out, err := fn(&in)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(out); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
}
type HelloIn struct {
}
type HelloOut struct {
}
func Hello(in *HelloIn) (*HelloOut, error) {
return &HelloOut{}, nil
}
// Usage
mux := http.NewServeMux()
mux.Handle("/hello", RPC(Hello))
The long-form equivalent is RPC[HelloIn, HelloOut](Hello)
. This also works with type constraints when you have a single type. In the following example, we introduce a Func
constraint:
type Func[In, Out any] interface {
func(in *In) (*Out, error)
}
Then adjusting the RPC function to the following:
func RPC[In, Out any, Fn Func[In, Out]](fn Fn) http.Handler {
// ...
}
And type inference continues to work as expected.
Problem
If you introduce another type like the following:
type Func[In, Out any] interface {
func(in *In) (*Out, error) | func(ctx context.Context, in *In) (*Out, error)
}
Then type inference no longer works. You'll be greeted with:
./main.go:66:26: cannot infer In
To fix this, you need to specify the types:
// Usage
mux := http.NewServeMux()
mux.Handle("/hello", RPC[HelloIn, HelloOut](Hello))
Proposal
It'd be great if type inference could infer more complex types. It does seem to work with basic type constraints, which is awesome:
type StringOrInt interface {
string | int
}
func print[T StringOrInt](t T) {
switch t := any(t).(type) {
case string:
println(t)
case int:
println(t)
}
}
// usage
print(10) // works!
print("hello") // works!
Could this be extended to support more complex types?
Thanks for your consideration!
Metadata
Metadata
Assignees
Type
Projects
Status