将 func(T) 转换为 func(any)
Convert func(T) to func(any)
我希望能够在结构的两个字段之间强制执行相似性,但在映射或切片中也有几个这样的结构。
这是我的问题的一个简化示例:
package main
type foo[T any] struct {
f func() T
v T
}
type bar struct {
x []*foo[any]
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[any]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
编译器报错
./prog.go:13:33: cannot use f (variable of type func() T) as type func() any in struct literal
有趣的是,如果我不需要在结构中有一个函数指针,这就可以工作。参见 https://go.dev/play/p/qXTmaa9PuVe
那么,有什么方法可以让我把 T 变成 any 吗?
我知道我可以使用 interface{} 来做到这一点并使用 reflect 来强制执行我想要的,但我确信仅使用泛型是可能的。
如果有办法解决我的问题,上下文是我正在制作一个标志包。重要的结构如下所示:
type flag[T any] struct {
value T
parse func(in string) (T, error)
// Other fields removed for simplicity...
}
type FlagSet struct {
// could flag[any] be replaced with a better answer?
flags map[string]*flag[any]
// Other fields removed for simplicity...
}
问题已关闭,所以我必须在这里回答问题的第二部分
could flag[any] be replaced with a better answer?
上面的答案是肯定的。
解决方案:
最初我虽然是这样的:“func()
适合 func()
而 any
适合 T
所以为什么我不能有 func() T
适合func() any
?”当然原因是 func() any
不是 any
所以它不能容纳 func() T
.
相反,您可以执行以下操作:
package main
type foo[T any] struct {
f func() T
v T
}
func (f *foo[_]) set() {
f.v = f.f()
}
type anyfoo interface {
set()
}
type bar struct {
x []anyfoo
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[T]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
but also have several of these structs in a map or slice
您不能这样做(以类型安全的方式)。例如的所有值切片必须具有相同的元素类型。如果你想存储不同的,你必须求助于 interface{}
并稍后输入 switch。
如果你使用正确的技术术语参数多态性而不是“泛型”,它不能解释发生了什么,你就会明白为什么 func(T) 和 func(any) 是不同的、不可转换的类型。
So, is there a way for me to turn a T into an any?
不,没有“泛型”之前的方式,也没有 post-“泛型”方式。将“转换为”视为 Go 允许的内容会有所帮助:“类型转换”和“赋值”。您可以将任何 T 类型的变量分配给任何类型的变量。
您可以通过使用适配器函数(闭包)来解决您的问题:
w := func(a any){ f(a.(T)) }
b.x = append(b.x, &foo[any]{w})
我希望能够在结构的两个字段之间强制执行相似性,但在映射或切片中也有几个这样的结构。
这是我的问题的一个简化示例:
package main
type foo[T any] struct {
f func() T
v T
}
type bar struct {
x []*foo[any]
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[any]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
编译器报错
./prog.go:13:33: cannot use f (variable of type func() T) as type func() any in struct literal
有趣的是,如果我不需要在结构中有一个函数指针,这就可以工作。参见 https://go.dev/play/p/qXTmaa9PuVe
那么,有什么方法可以让我把 T 变成 any 吗?
我知道我可以使用 interface{} 来做到这一点并使用 reflect 来强制执行我想要的,但我确信仅使用泛型是可能的。
如果有办法解决我的问题,上下文是我正在制作一个标志包。重要的结构如下所示:
type flag[T any] struct {
value T
parse func(in string) (T, error)
// Other fields removed for simplicity...
}
type FlagSet struct {
// could flag[any] be replaced with a better answer?
flags map[string]*flag[any]
// Other fields removed for simplicity...
}
问题已关闭,所以我必须在这里回答问题的第二部分
could flag[any] be replaced with a better answer?
上面的答案是肯定的。
解决方案:
最初我虽然是这样的:“func()
适合 func()
而 any
适合 T
所以为什么我不能有 func() T
适合func() any
?”当然原因是 func() any
不是 any
所以它不能容纳 func() T
.
相反,您可以执行以下操作:
package main
type foo[T any] struct {
f func() T
v T
}
func (f *foo[_]) set() {
f.v = f.f()
}
type anyfoo interface {
set()
}
type bar struct {
x []anyfoo
}
func baz[T any](b *bar, f func() T) {
b.x = append(b.x, &foo[T]{f: f})
}
func main() {
var b bar
baz(&b, func() int { return 0 })
}
but also have several of these structs in a map or slice
您不能这样做(以类型安全的方式)。例如的所有值切片必须具有相同的元素类型。如果你想存储不同的,你必须求助于 interface{}
并稍后输入 switch。
如果你使用正确的技术术语参数多态性而不是“泛型”,它不能解释发生了什么,你就会明白为什么 func(T) 和 func(any) 是不同的、不可转换的类型。
So, is there a way for me to turn a T into an any?
不,没有“泛型”之前的方式,也没有 post-“泛型”方式。将“转换为”视为 Go 允许的内容会有所帮助:“类型转换”和“赋值”。您可以将任何 T 类型的变量分配给任何类型的变量。
您可以通过使用适配器函数(闭包)来解决您的问题:
w := func(a any){ f(a.(T)) }
b.x = append(b.x, &foo[any]{w})