代码之家  ›  专栏  ›  技术社区  ›  domoarigato

golang插件可以用于工厂功能吗?

  •  4
  • domoarigato  · 技术社区  · 6 年前

    我在golang插件模块中有以下代码:

    加油

    package main
    
    import "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)
    }
    

    它被编译为.so对象并在另一个程序中使用:

    package main
    
    import (
        "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
    }
    

    我能查到 Thing ,并致电 Say()

    first thing - 1 panic: interface conversion: *main.thingFactory is not main.GetSayer: missing method Make

    即使运行时将第一个符号识别为 Sayer 它不承认这一点 thingFactory 显然有一个Make()方法,它应该返回同样是Sayer的东西。

    2 回复  |  直到 6 年前
        1
  •  2
  •   icza    6 年前

    thingFactory (更准确地说 *thingfactory GetSayer

    Make(string) Sayer
    

    你有:

    Make(string) thing
    

    所以(首先)你必须改变 thingFactory.Make()

    type Sayer interface {
        Say() string
    }
    
    func (t thingFactory) Make(s string) Sayer {
        th := New(s)
        return &th
    }
    

    在这之后,它仍然不起作用。这是因为插件的 Sayer 类型与主应用程序的类型不同 塞耶 类型但它们必须相同,才能实现主应用程序的 盖特赛耶 界面

    一个解决方案是将业务“外包” 塞耶 接口到它自己的包,并在插件和主应用程序中使用这个通用的共享包。

    让我们创建一个新包,称之为 subplay :

    package subplay
    
    type Sayer interface {
        Say() string
    }
    

    导入此软件包并在插件中使用它:

    package main
    
    import (
        "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
    }
    

    并在主应用程序中导入和使用它:

    package main
    
    import (
        "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
    }
    

    现在它将工作,输出将是:

    first thing - 1
    how about me? - 1
    how about me? - 2
    

    go 1.8 plugin use custom interface

    How do Go plugin dependencies work?

        2
  •  1
  •   Mostafa Solati    6 年前

    你的pluginmake方法应该返回一个Sayer对象,而不是其他东西

    type Sayer interface {
        Say() string
    }
    func (t *thingFactory) Make(s string) Sayer {
        return New(s)
    }