我想做的事情:
我有一个库包,它定义了几种类型,都实现了给定的接口。在整个代码中,涉及回调,而不是在我为其定义类型的任何地方编写回调类型。
type Foo interface {
Bar()
}
type MyCallback func(f Foo)
type CoolFoo int
type BadFoo int
func (cf *CoolFoo) Bar(cb MyCallback) {
}
func (bf *BadFoo) Bar(cb MyCallback) {
}
然后从使用该库的客户端代码开始,我想使用回调调用。如果我使用接口类型调用它,它可以工作:
cf := &CoolFoo{}
cf.Bar(func(f packageName.Foo) {
})
但我宁愿在我的IDE中有更多的自我记录代码和正确的类型提示,所以我尝试使用implementsor类型调用它,例如:
cf := &CoolFoo{}
cf.Bar(func(f packageName.CoolFoo) {
})
无法编译,错误:
不能使用func literal(类型为func(packageName.CoolFoo))作为类型 cf.Bar
参数中的packageName.MyCallback
这是不可能的,还是我犯了一些假的错误?我在开发方面不是很有经验,而且我已经尝试过环顾四周,但在这里找不到解决方案。
我发现它将它作为Foo或界面{}传递,然后在回调中投射到我想要的内容,但我想避免它,因为它感觉很乱
感谢您的帮助
答案 0 :(得分:3)
函数签名是func(f Foo)
,因此正是必须传递的内容。原因很简单:如果您的方法需要该签名的回调函数,它可以传入任何实现Foo 的类型。如果您传入的函数只接受CoolFoo
,则调用者仍然可以传递BadFoo
,因为您定义的类型允许它。因此,编译器要求类型精确匹配。同样,如果您的回调函数试图转换为具体类型,但这不是传递给它的类型,它将失败,因为您正在做出代码不支持的假设。
如果您的回调只会传入CoolFoo
,那么这可能是您在签名中使用的类型。如果CoolFoo
和BadFoo
每个只会将各自的类型传递给他们的回调,那么您可能需要两个不同的回调签名。如果它们真的可以互换,那么你描述的情况(专门用CoolFoo
执行的函数)不是语言的问题,这是你设计的一个问题。