If I write a generic function in Golang, I can print the type of either of the arguments to the function like this, which provides some insight into the type parameter:
func foo[T any](a T, b T) string {
return fmt.Sprintf("%v and %v are of type %T", a, b, a)
}
However, if I modify the function to take a slice instead:
func foo[T any](args ...T) string {
return fmt.Sprintf("% v are of type %T", args, args)
}
this will not print what I would prefer as calling foo[int]
will mean that args
has a type of []int
whereas I want to print int
. I could modify this to print args[0]
instead but that means I also have to check for the case where args
is empty and, in that case, I don't have a way to get the type of args
. I could also use reflection to get the type, but since it's a generic function, I should also know this at compile-time.
Is there a way I can get name of T
at compile time without having to print the type of any arguments or through reflection?
CodePudding user response:
Is there a way I can get name of T at compile time without having to print the type of any arguments or through reflection?
No
You need reflection for this.
CodePudding user response:
Printing the type name at compile time is not possible. Both fmt
and reflect
functions (which fmt
uses) are run time operations. You might be able to find out the type of some expression with static analysis but again this is orthogonal to run-time printing.
Anyway at run time, if the type parameter list captures the base type of a composite type, including a vararg slice, you can simply print it by declaring a new variable of that type. The idiom *new(T)
in particular allows to do it with one-liners:
func foo[T any](args ...T) string {
return fmt.Sprintf("% v are of type %T", args, *new(T))
}
Calling that as foo(1,2,3)
now gives the string:
"[1 2 3] are of type int"
Yes, the compiler is smart enough to know that *new(T)
doesn't escape to the heap.