How to work with un-exported interfaces
You can use go bug to have a cool, automatically filled out bug template, or
fill out the template below.
Describe the bug
Some Providers rely on locally-defined non-exported interfaces. In Go the interface contract is loosely coupled and therefore those interfaces do not need to be exported in order for the provider/constructor to be called as the resolution will be dynamic at compile-time.
In the documentation, wire.Bind is the adviced approach to wire Structs into interface arguments, the issue is that in case the interface argument is not exported wire compilation fails because it has no visibility over the non-exported interface.
To Reproduce
Project structure:
❯ tree
.
├── bar
│ └── bar.go
├── foo
│ └── foo.go
├── go.mod
├── go.sum
├── main.go
├── wire.go
└── wire_gen.go
bar.go:
package bar
import "fmt"
type sayer interface {
Say() string
}
func NewBar(s sayer) *Bar {
return &Bar{
sayer: s,
}
}
type Bar struct {
sayer sayer
}
func (b *Bar) Start() {
fmt.Printf("%s\n", b.sayer.Say())
}
foo.go
package foo
func NewFoo() *Foo {
return &Foo{}
}
type Foo struct {
}
func (f *Foo) Say() string {
return "I'm foo"
}
main.go
package main
func main() {
b := InitializeBar()
b.Start()
}
wire.go (does not compile)
//go:build wireinject
// +build wireinject
package main
import (
"github.com/google/wire"
"wire-test/bar"
)
import "wire-test/foo"
func InitializeBar() *bar.Bar {
wire.Build(foo.NewFoo, wire.Bind(new(bar.sayer), new(*foo.Foo)), bar.NewBar)
return &bar.Bar{}
}
❯ wire
wire: /Users/rodrigo.broggi/repo/wire-test/wire.go:13:43: sayer not exported by package bar
wire: generate failed
Interestingly enough if we change the bar interface to be exported everything compiles correctly and code is well generated, furthermore, the generated code makes no references at all to the exported interface so theoretically one could refactor the generated code along with the interface to make those non-exporeted again.
Is there a way to overcome that?
Expected behavior
A way to generate injectors also for providers that use non-exported interfaces.
Version
latest (0.5.0)
Additional context
Add any other context about the problem here.
The explicit binding is there so when multiple structs implement the same interface, wire doesn't have to guess user's intent. The final generated code doesn't really need to reference that interface because of the loose coupling you mentioned. That FAQ points to #242, which I think would solve this problem as well. I'm not sure about the status of #242.
Besides #242, I can't think of a solution other than either exporting the interface (which may not be preferred, or even impossible), or refactor after generation.