【问题标题】:Is it possible to share a custom data type between a go plugin and an application?是否可以在 go 插件和应用程序之间共享自定义数据类型?
【发布时间】:2018-05-24 18:28:41
【问题描述】:

我知道可以查找已导出的 go-plugin 符号并将它们键入到 interface 中。但是,我想知道是否有办法将它们键入到结构中,例如。有什么办法吗?

例如:

plugin.go

package main

type Person struct {
    Name string
}

var (
    P = Person{
        Name: "Emma",
    }
)

app.go

package main

import (
    "fmt"
    "plugin"
    "os"
)

func main() {
    plug, err := plugin.Open("./plugin.so")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    sym, err := plug.Lookup("P")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    var p Person
    p, ok := sym.(Person)
    if !ok {
        fmt.Println("Wrong symbol type")
        os.Exit(1)
    }

    fmt.Println(p.Name) 
}

Person 的符号 P 是在调用 plug.Lookup 时找到的。但是,我无法将 P 类型断言为 Person,我得到一个执行时间错误。在本例中,“符号类型错误”

有没有办法实现这一点,或者在插件和应用程序之间共享数据的唯一方法是使用接口?

谢谢。

【问题讨论】:

    标签: go plugins


    【解决方案1】:

    main 包中定义的标识符不能从其他包中引用,因此从插件导出的标识符不能与您在主应用程序中的类型相同。即使您在插件文件和主应用程序中复制 Person 类型,类型断言也会失败,因为它们不是同一类型!

    但是可以在单独的包中定义类型,并在插件和主应用程序中使用相同的包。然后,您可以从插件中查找的符号中键入断言此类型。

    看这个例子:

    在自己的包中定义的单独类型:

    package filter
    
    type Filter struct {
        Name string
        Age  int
    }
    

    插件代码:

    package main
    
    import (
        "play/filter"
    )
    
    var MyFilter = filter.Filter{
        Name: "Bob",
        Age:  21,
    }
    
    func CreateFilter() filter.Filter {
        return filter.Filter{
            Name: "Bob",
            Age:  21,
        }
    }
    

    主应用:

    package main
    
    import (
        "fmt"
        "log"
        "os"
        "play/filter"
        "plugin"
    )
    
    func main() {
        p, err := plugin.Open("plugin.so")
        if err != nil {
            log.Fatal(err)
        }
        mf, err := p.Lookup("MyFilter")
        if err != nil {
            log.Fatal(err)
        }
        f, ok := mf.(*filter.Filter)
        if !ok {
            log.Fatal("Wrong symbol type")
        }
    
        fmt.Printf("%+v\n", f)
    }
    

    运行主应用,输出为:

    &{Name:Bob Age:21}
    

    您可能会注意到,插件MyFilter 中的导出标识符是一个非指针类型的变量,但我们从导出的符号中对指针类型进行了类型断言。这是因为如果你查找一个变量,你会得到一个指向它的指针,否则你不能修改变量的值,你只能修改副本。这在这个答案中有详细说明:Plugin symbol as function return

    如果我们查找插件导出的另一个符号,情况并非如此:CreateFilter() 函数,它返回一个非指针类型的值filter.Filter

    cf, err := p.Lookup("CreateFilter")
    if err != nil {
        log.Fatal(err)
    }
    
    createFilter, ok := cf.(func() filter.Filter)
    if !ok {
        log.Fatal("Wrong function type")
    }
    f2 := createFilter()
    fmt.Printf("%+v\n", f2)
    

    运行这段代码,输出将是:

    {Name:Bob Age:21}
    

    查看相关问题:go 1.8 plugin use custom interface

    另外请注意,如果您更改插件和主应用程序常用的filter 包,您还必须重新构建插件。尝试在不重新构建插件的情况下运行应用程序将在plugin.Open() 调用期间导致错误。详情见How do Go plugin dependencies work?

    【讨论】:

      猜你喜欢
      • 2019-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-29
      相关资源
      最近更新 更多