是否可以在go插件和应用程序之间共享自定义数据类型? [英] Is it possible to share a custom data type between a go plugin and an application?

查看:82
本文介绍了是否可以在go插件和应用程序之间共享自定义数据类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道可以查找导出的go-plugin符号并将其断言到接口中.但是,我想知道是否有一种方法可以将它们断言为一个结构.有办法吗?

例如:

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

调用 plug.Lookup 时会找到符号P,它是 Person .但是,我无法将P输入为 Person ,但是出现执行时间错误.在此示例中,符号类型错误" .

是否有实现此目的的方法,还是在插件和应用程序之间共享数据的唯一方法是使用接口?

谢谢.

解决方案

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中的导出标识符是非指针类型的变量,但是我们从导出的符号中对指针类型进行了类型声明.这是因为如果您查找变量,您将获得指向它的指针,否则您将无法修改变量的值,而只能修改副本.此答案中对此进行了详细说明:插件符号作为函数返回

如果我们查找插件导出的另一个符号则不是这种情况: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}

请参阅相关问题:转到1.8插件使用自定义界面

还请注意,如果您更改了插件和主应用程序通常使用的filter软件包,则还必须重新构建插件.尝试在不重建插件的情况下运行应用程序将导致在plugin.Open()调用期间出错.有关详细信息,请参见 Go插件依赖项如何工作?

I know that it is possible to look up for go-plugin symbols that were exported and type assert them into an interface. However, I wonder if is there a way to type assert them into a struct, for example. Is there a way to do it?

For example:

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

The symbol P, which is a Person, is found when plug.Lookup is called. However, I can't type-assert P into Person, I get an execution time error. In this example, "Wrong symbol type".

Is there a way to achieve this or the only way to share data between the plugin and the application is using interfaces?

Thanks.

解决方案

Identifiers defined in the main package cannot be referred to from other packages, so an exported identifier from a plugin cannot be the same type what you have in your main app. Even if you would duplicate the Person type both in the plugin's file and in your main app, type assertion would fail because they are not the same type!

But it is possible to define the type in a separate package, and use this same package in the plugin and in the main app. And then you can type assert this type from a symbol you lookup from the plugin.

See this example:

The separate type defined in its own package:

package filter

type Filter struct {
    Name string
    Age  int
}

Plugin code:

package main

import (
    "play/filter"
)

var MyFilter = filter.Filter{
    Name: "Bob",
    Age:  21,
}

func CreateFilter() filter.Filter {
    return filter.Filter{
        Name: "Bob",
        Age:  21,
    }
}

The main app:

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

Running the main app, the output is:

&{Name:Bob Age:21}

What you may notice is that the exported identifier in the plugin MyFilter is a variable of non-pointer type, yet we type-asserted a pointer type from the exported symbol. This is because if you lookup a variable, you will get a pointer to it, else you could not modify the value of the variable, you could only modify the copy. This is detailed in this answer: Plugin symbol as function return

This is not the case if we lookup the other symbol our plugin exports: the CreateFilter() function which returns a value of non-pointer type 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)

Running this code, the output will be:

{Name:Bob Age:21}

See related question: go 1.8 plugin use custom interface

Also note that if you change the filter package used commonly by the plugin and the main app, you also have to rebuild the plugin. Attempting to run the app without rebuilding the plugin will result in an error during the plugin.Open() call. For details, see How do Go plugin dependencies work?

这篇关于是否可以在go插件和应用程序之间共享自定义数据类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆