Идентификаторы, определенные в пакете main
, нельзя ссылать из других пакетов, поэтому экспортированный идентификатор из плагина не может быть того же типа, что и у вас в основном приложении. Даже если вы дублируете тип Person
как в файле плагина, так и в вашем основном приложении, утверждение типа не удастся, потому что они не одного типа!
Но можно определить тип в отдельном пакете и использовать этот же пакет в плагине и в основном приложении. И тогда вы можете напечатать assert этот тип из символа, который вы ищете из плагина.
См. Этот пример:
Отдельный тип, определенный в его собственной упаковке:
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}
См. Связанный вопрос: Плагин Go 1.8 использует пользовательский интерфейс
Также обратите внимание, что если вы измените пакет filter
, обычно используемый плагином и основным приложением, вам также придется перестроить плагин. Попытка запустить приложение без перестройки плагина приведет к ошибке во время вызова plugin.Open()
. Подробнее см. Как работают зависимости плагина Go?