使用接口定义的回调参数,使用实现调用

What I'm trying to do:

I have a library package which defines a few types, all implementing a given interface. Throughout the code, there are callbacks involved, and instead of writing the callback type everywhere I defined a type for it.

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) {
}

Then later from client code using that library, I want to call using callbacks. If I call it by using the interface type it works:

cf := &CoolFoo{}

cf.Bar(func(f packageName.Foo) {
})

But I would rather have more self documenting code, and proper type hinting in my IDE, so I try to call it using the implementor type, such as this:

cf := &CoolFoo{}

cf.Bar(func(f packageName.CoolFoo) {
})

Which fails to compile, with the error:

cannot use func literal (type func(packageName.CoolFoo)) as type packageName.MyCallback in argument to cf.Bar

Is it not possible, or am I making some dummy mistake ? I'm not very experienced in go dev, and I've tried looking around, but couldn't find the solution here.

What I've found is passing it as a Foo or an interface{} and then casting in the callback to what I want, but I would like to avoid it as it feels messy

Thanks for any help

The function signature is func(f Foo), so that is exactly what must be passed. The reason is simple: if your method expects a callback function of that signature, it can pass in any type that implements Foo. If you passed in a function that only accepted CoolFoo, the caller could still pass in BadFoo, because the types you've defined allow it. Thus, the compiler requires that the types match precisely. Likewise, if your callback function tries to cast to a concrete type, but that isn't the type that was passed to it, it will fail, because you're making an assumption that isn't supported by the code.

If your callback will only pass in CoolFoo, maybe that should be the type you use in the signature. If CoolFoo and BadFoo will each only pass in their respective types to their callbacks, maybe you need two different callback signatures. If they really are interchangeable, then the case you describe (a function taking CoolFoo specifically) isn't a problem with the language, it's a problem with your design.