Trying to use generics with time.Time
.
The general goal was to accept time.Time
or milliseconds as int64
This code return the error:
Cannot use 'at' (type T) as the type time.Time
type SomeTime struct {
At time.Time
}
func PointFactory[T time.Time](at T) *SomeTime {
return &SomeTime{
At: at,
}
}
Is it possible to pass time.Time
as parameter to generic function?
Thanks
CodePudding user response:
The closest you can get is to cast your T param to any then use a type switch to make the desired structs:
package main
import (
"fmt"
"time"
)
type SomeTime struct {
At time.Time
}
func PointFactory[T time.Time | int64](at T) *SomeTime {
v := any(at)
switch v.(type) {
case time.Time:
fmt.Println("time")
return &SomeTime{
At: v.(time.Time),
}
case int64:
fmt.Println("int")
return &SomeTime{
At: time.Unix(v.(int64), 0),
}
}
return nil
}
func main() {
fmt.Println(PointFactory(int64(6)))
fmt.Println(PointFactory(time.Now()))
}
Output:
int
&{1970-01-01 00:00:06 0000 UTC}
time
&{2009-11-10 23:00:00 0000 UTC m= 0.000000001}
This is because the decision of the Go team:
In an earlier version of this design, we permitted using type assertions and type switches on variables whose type was a type parameter, or whose type was based on a type parameter. We removed this facility because it is always possible to convert a value of any type to the empty interface type, and then use a type assertion or type switch on that. Also, it was sometimes confusing that in a constraint with a type set that uses approximation elements, a type assertion or type switch would use the actual type argument, not the underlying type of the type argument (the difference is explained in the section on identifying the matched predeclared type)
CodePudding user response:
You may declare multiple type as such:
func say[T string | int](msg T) {
fmt.Println(msg)
}
func main() {
say(1)
say("hello")
}
See playground
Now as per your question, may you redefine your functions ? You may use:
PointFromInt(n int) *SomeTime {...}
PointFromTime(t time.Time) *SomeTime {...}
Your usecase may not be a good candidate for generics. Or regular typed function may do a better job.
CodePudding user response:
If the Sometime
struct is expected to accept time.Time
or int64
then it needs to declare it, the methods set the value to At
what type is available
type SomeTime[T time.Time | int64] struct {
At T
}
func PointFactoryTime(at time.Time) *SomeTime[time.Time] {
return &SomeTime[time.Time]{
At: at,
}
}
func PointFactoryInt64(at int64) *SomeTime[int64] {
return &SomeTime[int64]{
At: at,
}
}
CodePudding user response:
package main
import (
"fmt"
"time"
)
func main() {
fmt.Printf("%v\n", PointFactory(time.Now()).At)
fmt.Printf("%v\n", PointFactory(time.Now().Unix()).At)
}
type SomeTime[T time.Time | int64] struct {
At T
}
func PointFactory[T time.Time | int64](at T) *SomeTime[T] {
return &SomeTime[T]{
At: at,
}
}