2017-04-03 47 views
3

这是关于Go插件初始化的一般问题。Go插件变量初始化

我想在GO程序中将某个程序包制作为Go插件。

该软件包(比如说mypackage)有一个变量,该变量用来自可执行文件中某个包的函数调用进行初始化。 (例如interface Logger类型的变量,其是由一个logger.CreateLogger函数被初始化。)

为了使mypackage一个插件,我需要创建一个main包,嵌入mypackage内部main,并在包输出的API Initmain它接受一个功能,可以让我一个记录器。

我想这样做,以减少我的插件的依赖关系。 mypackage插件应取决于interface Logger而不是Logger的实现。

现在的问题是初始化,在可执行文件的情况下,初始化可能如下发生:

package mypackage 

var dlog = logger.CreateLogger("mypackage") 

而且记录器可以在任何mypackage功能func init()使用。

转换为插件后,无法像这样初始化。必须在调用main.Init后稍后进行初始化。

当插件是Opened时调用func init,所以它不能用于初始化变量。

唯一的解决方案似乎是创建每个包的函数,并从main包中的导出函数调用它。

package mypackage 

var dlog Logger 

func Init(f createLoggerType){ 
    dlog = f() 
    yetanotherpackage.Init(f) 
} 

package main 

func Init(f createLoogerType) { 
    mypackage.Init(f) 
    anotherpackage.Init(f)   
} 

有没有更好的方法来初始化?我试图检查github.com/facebookgo/inject,但无法弄清楚如何在插件的情况下使用它。

回答

1

您的解决方案没有问题,但是如果您希望能够在变量声明和包init()函数中使用它,则可以这样做。我也认为用这种方式使用插件更容易,但是这需要在主应用程序和插件之间使用通用的共享包。

一种选择是创建一个“存储”包,它可以存储工厂功能或预先创建的记录器。

比方说,Logger接口定义为mylogger

package mylogger 

type Logger interface { Log(string) } 

store例如:

package store 

import "mylogger" 

var LoggerFactory func(string) mylogger.Logger 

而在你的主应用程序初始化加载前/打开mypackage插件:

package main 

import "store" 

func main() { 
    store.LoggerFactory = logger.CreateLogger 

    // Now proceed to load/open mypackage plugin 
} 

然后mypackage插件可能是这样的:

package mypackage 

import "store" 

var dlog = store.LoggerFactory("mypackage") 
+0

谢谢您的回答。 1)记录器是由框架创建的,所以我无法从插件中创建记录器。记录器框架位于打开插件的可执行文件中,2)我的观点是让插件本身不包含记录器框架。而是取决于在加载插件时将被初始化的记录器接口。插件只需要告诉它需要哪种类型的记录器。之后插件在界面上工作。 3)'init'不能被使用,因为在任何'plugin.Lookup'可以执行之前调用'init' – weima

+0

@weima请参阅编辑答案。现在插件不会创建记录器,它不会引用记录器实现。 – icza

+0

换句话说,你的解决方案是:不是将'createLoggerType'作为参数传递给它的'InitPlugin'函数,而是在可执行文件中创建一个新的包,它在导出的变量中保存相同的函数,这个'package商店“有一个最小的依赖关系。这正是我想要避免的,插件除了提供给插件的接口和实现之外,还导入其他任何东西,而不是插件来决定实现。以及如果我想在运行时决定记录器的工厂,取决于插件类型。 – weima