I have the following code in a golang plugin module:plug.gopackage mainimport "fmt"var ( Thing = New("first thing") ThingFactory = thingFactory{})type thing struct { i int s string}func New(s string) thing { return thing{s: s}}func (t *thing) Say() string { t.i++ return fmt.Sprintf("%s - %d", t.s, t.i)}type thingFactory struct{}func (t thingFactory) Make(s string) thing { return New(s)}it is compiled as a .so object and used in another program:main.gopackage mainimport ( "fmt" "plugin")func main() { p, err := plugin.Open("../plug/plug.so") if err != nil { panic(err) } symbol, err := p.Lookup("Thing") if err != nil { panic(err) } thing := symbol.(Sayer) fmt.Println(thing.Say()) symbol, err = p.Lookup("ThingFactory") // <-problems start here if err != nil { panic(err) } factory := symbol.(GetSayer) madeThing := factory.Make("how about me?") fmt.Println(madeThing.Say()) fmt.Println(madeThing.Say())}type Sayer interface { Say() string}type GetSayer interface { Make(string) Sayer}I'm able to lookup the Thing, and call Say() on it, but the second interface conversion panics:first thing - 1panic: interface conversion: *main.thingFactory is not main.GetSayer: missing method Makeeven though the runtime recognizes the first symbol as a Sayer it doesn't recognize that thingFactory obviously has a Make() method, which should return something that is also a Sayer.Am I missing something obvious here? 解决方案 The first problem is that in your plugin thingFactory (more precicely *thingfactory) does not have a method described in your main app's GetSayer interface:Make(string) SayerYou have:Make(string) thingSo (first) you have to change thingFactory.Make() to this:type Sayer interface { Say() string}func (t thingFactory) Make(s string) Sayer { th := New(s) return &th}After this it still won't work. And the reason for this is because the plugin's Sayer type is not identical to your main app's Sayer type. But they must be the same in order to implement your main app's GetSayer interface.One solution is to "outsource" the Sayer interface to its own package, and use this common, shared package both in the plugin and in the main app.Let's create a new package, call it subplay:package subplaytype Sayer interface { Say() string}Import this package and use it in the plugin:package mainimport ( "fmt" "path/to/subplay")var ( Thing = New("first thing") ThingFactory = thingFactory{})type thing struct { i int s string}func New(s string) thing { return thing{s: s}}func (t *thing) Say() string { t.i++ return fmt.Sprintf("%s - %d", t.s, t.i)}type thingFactory struct{}func (t thingFactory) Make(s string) subplay.Sayer { th := New(s) return &th}And also import and use it in the main app:package mainimport ( "fmt" "path/to/subplay" "plugin")func main() { p, err := plugin.Open("../plug/plug.so") if err != nil { panic(err) } symbol, err := p.Lookup("Thing") if err != nil { panic(err) } thing := symbol.(subplay.Sayer) fmt.Println(thing.Say()) symbol, err = p.Lookup("ThingFactory") if err != nil { panic(err) } factory := symbol.(GetSayer) madeThing := factory.Make("how about me?") fmt.Println(madeThing.Say()) fmt.Println(madeThing.Say())}type GetSayer interface { Make(string) subplay.Sayer}Now it will work, and output will be:first thing - 1how about me? - 1how about me? - 2See related questions:go 1.8 plugin use custom interfaceHow do Go plugin dependencies work? 这篇关于golang插件可以用于工厂功能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-16 10:29