Go 使用接口作为参数创建另一个包的等效接口
我正在练习编写惯用的Go代码,发现接口应该在使用它们的包中声明,因为它们是隐式的。然而,我遇到了这种情况,在第二个包(包b)中,我希望一个函数调用包a中结构的接收方函数,而不紧密耦合它 因此,很自然,我在包b中声明了一个接口,该接口带有我想从包a调用的函数的签名。问题是这个函数接受一个特定类型的参数,该参数是包a中声明的接口。因为我不希望包b导入包a,所以我在包b中定义了一个接口,该接口的签名与包a中的签名完全相同。下面的游乐场链接显示了示例代码 此代码不可编译。所以这里的问题是,我是否错误地使用了接口,或者应该在单独的包中定义具体的类型,或者最后,对于我试图解决的问题,是否有更好的代码模式 编辑:为了澄清,包a和包b不相互导入。main()代码存在于一个单独的包中,该包将这两个代码连接起来。解决方案 有一个类型在两个包a和B中使用。包a导入包B 您必须避免循环依赖,因此有三种选择:Go 使用接口作为参数创建另一个包的等效接口,go,interface,Go,Interface,我正在练习编写惯用的Go代码,发现接口应该在使用它们的包中声明,因为它们是隐式的。然而,我遇到了这种情况,在第二个包(包b)中,我希望一个函数调用包a中结构的接收方函数,而不紧密耦合它 因此,很自然,我在包b中声明了一个接口,该接口带有我想从包a调用的函数的签名。问题是这个函数接受一个特定类型的参数,该参数是包a中声明的接口。因为我不希望包b导入包a,所以我在包b中定义了一个接口,该接口的签名与包a中的签名完全相同。下面的游乐场链接显示了示例代码 此代码不可编译。所以这里的问题是,我是否错误地
例如,看看这个包。使用另一个包中定义的接口
io.Reader
。使用另一个包中定义的接口io.Writer
。IIUC,您的问题不是关于包,而是归结为函数(或方法)
可以类型转换为另一个函数,该函数接受具有等效参数的参数,但
不同的接口类型
像这样的:()
编译错误:/g.go:8:26:无法将f1(类型func(I1))转换为类型func(接口{})
答案似乎是否定的,因为GO没有考虑<代码> FUNC(I1)< /代码>。 相当于
func(接口{})
。政府是这样说的
函数类型表示具有相同参数和结果类型的所有函数的集合
类型func(I1)
和func(接口{})
不采用相同的参数,即使
I1
定义为接口{}
。您的代码无法编译类似的代码
原因是func(runner RunnerB)
与func(runner runner)
不同,因此*Manager
的方法集不是
接口runnerRegisterer
回到你原来的问题:
我正在练习编写惯用的Go代码,发现接口
应该在使用它们的包中声明,因为它们是
含蓄的
是的,这个想法很好,但它不适用于您的实现方式
我想是的。因为您希望有不同的
runnerRegisterer
并且它们都必须具有具有相同签名的方法
使用Runner
界面,可以在公共文档中定义Runner
地点。此外,如上所述,Go不允许您使用不同的接口
在方法中,无论如何都要签名
根据我对你想要达到的目标的理解,以下是我的想法
您应该重新安排代码:
runnerristerer
(注意:这是公共的)和Runner
定义在一个
包裹RunnerCoach
,并使用上述
接口。您的RunnerCoach
使用实现接口的类型,
所以它定义了它们Runner
接口在这里管理器
RunnerCoach
的包中定义了Runner
,因为它必须采用该类型
如果要用作RunnerRegisterer
,则作为参数但它不会编译,不是因为循环依赖关系。在上面的示例中,包A和包B不相互导入。其目的是main()(称为package M)代码通过接口将两个包连接在一起。问题是RunnerB(pkg b)接口未检测到与Runner(pkg a)接口等效,尽管它们定义了相同的函数签名,因此类型检查失败。是的,我知道。我尝试了你的游乐场代码,并在两个包中使用相同的接口类型对其进行了调整。如果我不理解这个问题,我就不会这样回答。经过编辑的答案更清楚,并且提供了相关的参考,说明为什么它不是一个一致的公理。谢谢
package main
import (
"fmt"
"log"
)
func main() {
manager := &Manager{}
coach := NewRunnerCoach(manager)
fmt.Println("Done")
}
// package a
type Runner interface {
Run()
}
type Manager struct {
}
func (o *Manager) RegisterRunner(runner Runner) {
log.Print("RegisterRunner")
}
func (o *Manager) Start() {
log.Print("Start")
}
// package b
type RunnerCoach struct {
runner *FastRunner
}
func NewRunnerCoach(registerer runnerRegisterer) *RunnerCoach {
runnerCoach := &RunnerCoach{&FastRunner{}}
registerer.RegisterRunner(runnerCoach.runner)
return runnerCoach
}
type FastRunner struct {
}
func (r *FastRunner) Run() {
log.Print("FastRunner Run")
}
// define ther registerer interface coach is accepting
type runnerRegisterer interface {
RegisterRunner(runner RunnerB)
}
// declaring a new interface with the same signature because we dont want to import package a
// and import Runner interface
type RunnerB interface {
Run()
}
package main
type I1 interface{}
func f1(x I1) {}
func main() {
f := (func(interface{}))(f1)
f(nil)
}