将time.Time作为参数传递给通用函数

huangapple go评论67阅读模式
英文:

Passing time.Time as parameter to generic function

问题

尝试在time.Time中使用泛型。
总体目标是接受time.Time或毫秒作为int64

这段代码返回错误:

> 无法将't'(类型T)用作time.Time类型

type SomeTime struct {
	At        time.Time
}

func PointFactory[T time.Time](at T) *SomeTime {
	return &SomeTime{
		At:        at,
	}
}

是否可以将time.Time作为参数传递给泛型函数?
谢谢。

英文:

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

答案1

得分: 3

你可以将T参数转换为任意类型,然后使用类型切换来创建所需的结构体:

package main

import (
	"fmt"
	"time"
)

type SomeTime struct {
	At time.Time
}

func PointFactory[T interface{}](at T) *SomeTime {
	switch v := at.(type) {
	case time.Time:
		fmt.Println("time")
		return &SomeTime{
			At: v,
		}

	case int64:
		fmt.Println("int")
		return &SomeTime{
			At: time.Unix(v, 0),
		}

	}
	return nil

}

func main() {
	fmt.Println(PointFactory(int64(6)))
	fmt.Println(PointFactory(time.Now()))
}

输出结果:

int
&{1970-01-01 00:00:06 +0000 UTC}
time
&{2009-11-10 23:00:00 +0000 UTC m=+0.000000001}

这是因为Go团队的决定:

在此设计的早期版本中,我们允许在类型参数的类型或基于类型参数的类型上使用类型断言和类型切换。我们删除了这个功能,因为始终可以将任何类型的值转换为空接口类型,然后在其上使用类型断言或类型切换。此外,在使用近似元素的类型集的约束中,有时会令人困惑的是,类型断言或类型切换将使用实际的类型参数,而不是类型参数的基础类型(该差异在匹配的预声明类型的标识部分中有解释)。

PlayGround

英文:

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 {
	switch any(at).(type) {
	case time.Time:
		fmt.Println("time")
		return &SomeTime{
			At: v,
		}

	case int64:
		fmt.Println("int")
		return &SomeTime{
			At: time.Unix(v, 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)

答案2

得分: 1

你可以这样声明多个类型:

func say[T string | int](msg T) {
    fmt.Println(msg)
}

func main() {
    say(1)
    say("hello")
}

参见 playground

根据你的问题,你可以重新定义你的函数。你可以使用:

PointFromInt(n int) *SomeTime {...}
PointFromTime(t time.Time) *SomeTime {...}

你的用例可能不适合使用泛型。或者常规的类型化函数可能更适合。

英文:

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.

答案3

得分: 0

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,
	}
}
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,
	}
}
英文:
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,
	}
}

答案4

得分: 0

如果Sometime结构体预期接受time.Timeint64类型的值,那么它需要声明这个类型,并且方法将值设置为At,具体是哪种类型取决于可用的类型。

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,
	}
}
英文:

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,
	}
}

huangapple
  • 本文由 发表于 2022年9月23日 16:13:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/73824808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定