Home > Software engineering >  Passing time.Time as parameter to generic function
Passing time.Time as parameter to generic function

Time:09-24

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()))
}

PlayGround

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,
    }
}
  •  Tags:  
  • go
  • Related