Is there any way to take a string or an error as a generic parameter?
package controller
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type ServerError[T fmt.Stringer] struct {
Reason T `json:"reason"`
}
func ResponseWithBadRequest[T fmt.Stringer](c *gin.Context, reason T) {
c.AbortWithStatusJSON(http.StatusBadRequest, ServerError[T]{Reason: reason})
}
The above code contains a helper function tries to response an http request with a json containing one generic field that I would like it to be a string
or an error
.
But when I try to input a string:
string does not implement fmt.Stringer (missing method String)
which I find very amusing.
I tried to change T fmt.Stringer
to T string | fmt.Stringer
:
cannot use fmt.Stringer in union (fmt.Stringer contains methods)
I understand the reason is that string
in golang is a primitive data type without any method, I would like to know if there's a possible way to do this.
Update:
As @nipuna pointed out in the comment, error
is not a Stringer
either.
CodePudding user response:
Is there any way to take a string or an error as a generic parameter?
No. As stated, the constraint you are looking for is ~string | error
, which doesn't work because interfaces with methods can't be used in unions.
And error
is indeed an interface with the Error() string
method.
The sensible way to handle this is to drop generics and define Reason
as a string
:
type ServerError struct {
Reason string `json:"reason"`
}
You can find more details about that here: Golang Error Types are empty when encoded to JSON. The tl;dr is that error
can't shouldn't be encoded to JSON directly; you'll eventually have to extract its string message anyway.
So in the end you're going to do something like this with strings:
reason := "something was wrong"
c.AbortWithStatusJSON(http.StatusBadRequest, ServerError{reason})
and something like this with errors:
reason := errors.New("something was wrong")
c.AbortWithStatusJSON(http.StatusBadRequest, ServerError{reason.Error()})