Go generator函数,用于创建满足接口要求的值
我试图在一些代码中泛化超值类型。我需要做一大堆的值,然后对它们进行运算。API大致如下所示:Go generator函数,用于创建满足接口要求的值,go,Go,我试图在一些代码中泛化超值类型。我需要做一大堆的值,然后对它们进行运算。API大致如下所示: type Foo interface { A(string) error } func Run(foo_gen func () (Foo, error)) { ... } 另一方面,我有: type bar struct { ... } func (bar Bar) A (s string) { ... } func main() { foo_gen := func () (
type Foo interface {
A(string) error
}
func Run(foo_gen func () (Foo, error)) {
...
}
另一方面,我有:
type bar struct {
...
}
func (bar Bar) A (s string) {
...
}
func main() {
foo_gen := func () (bar, error) {
return bar{}, nil
}
mypackage.Run(foo_gen)
}
此操作失败,错误为:
cannot use foo_gen (type func () (bar, error)) as type func() (mypackage.Foo, error) in argument to mypackage.Run
我是新来的,所以我可能缺少一些基本的东西。我所期望的是,编译器会通过匹配方法类型(类似于记录子类型关系)尝试显式地将
bar
强制转换为Foo
,但情况似乎并非如此?这一解释可能令人惊讶,但实际上很简单
foo\u gen
定义为func()(foo,error)
,因此第一个返回值的类型为foo
,这是一个接口
任何接口类型的值都是具有两个指针的struct
:指向该接口值中实际包含的具体值和指向(表示)其类型的某个内部对象。下面是一个关于如何实现接口值的经典且非常好的解释(如果可能有点生疏的话)
您尝试匹配刚才讨论的签名的实际函数返回一个类型为Bar
的值作为其第一个返回值。该类型是struct
类型,与原始签名所期望的接口值无关。换句话说,为了使返回类型为
Bar
的函数满足期望接口类型为Foo
的签名,编译器必须生成代码,将返回的Bar
复制到堆中,并从中合成Foo
的值。虽然这可能是可行的,但这太含蓄了,在其他方面可能会令人惊讶
编译器不允许将片
[]T
分配给接口{}类型的变量。此错误的工程原因在@kostix的注释中给出。在类型级别上,这就是正在发生的情况
问题是go编译器无法将func()(bar,error))
提升为func()(Foo,error)
,因为一般来说go值不是
其结果是有几种方法可以解决这个问题
一种是更改函数的返回类型:
foo_gen := func () (Foo, error) {
return bar{}, nil
}
bar_gen := func () (bar, error){
return bar{}, nil
}
foo_gen := func() (Foo, error){
foobar, err := bar_gen()
return foobar, err
}
这是因为它能够轻松地将bar{}
值提升为Foo
值
如果我无法更改生成器功能(这也适用于通道等),另一种方法是将生成器包装到另一个功能中:
foo_gen := func () (Foo, error) {
return bar{}, nil
}
bar_gen := func () (bar, error){
return bar{}, nil
}
foo_gen := func() (Foo, error){
foobar, err := bar_gen()
return foobar, err
}
不,事实并非如此。签名必须逐字匹配。@Adrian套接字等如何工作?bc他们似乎导出了一个类型签名的联合?我不确定你们指的是什么,你们能告诉我显示这个的文档吗?这真的很有趣!我正在查找大约那个文档,但找不到它。这是否意味着这样的方法不可能工作?此外,这基本上是正确的答案,但实际解决问题的方法是更改函数的返回类型。(实际问题是它不能将
(unit->bar)
类型转换为(unit->Foo)
类型,但编译器可以在生成器函数内部进行转换,即它是一个子类型问题)@Cjen1,Go不能有“子类型问题”,因为它没有子类型。Go有OOP,但Go实现的OOP方法不包含继承的概念。完全围棋没有继承权。这种错误的思维模式可能正是让你对手头的问题感到困惑的原因。解决这个问题的一种方法就是让具体的foo_gen
(在main
中定义)将foo
作为其第一个返回值的类型。是的,我理解你关于go没有子类型的意思,但是ducktyping似乎只适用于原始值,而不适用于任何派生的值(函数、切片等),这意味着函数的返回类型不是协变的,这正是我想要说的。