我正在尝试静态编译一个groovy脚本来加速它的执行,但是如果使用命令行参数则无法使它工作。我的实际脚本要长得多,但我用于此问题的单行脚本完美地再现了我的错误。
使用以下脚本( test.groovy )
println(args.length)
这可以使用命令groovyc test.groovy
进行编译,并通过java命令java -cp .;%GROOVY_HOME%\lib\* test
运行,并且只打印使用的命令行参数的数量。
现在,如果我提供脚本( config.groovy )
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
并使用groovyc -configscript config.groovy test.groovy
进行编译,我收到错误
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
testing.groovy: 1: [Static type checking] - The variable [args] is undeclared.
@ line 1, column 9.
println(args.length)
^
1 error
当我尝试静态编译时,才会出现此错误。我可以通过将脚本包装在一个类中并将我的代码放在一个main方法(当然,这是编译器用脚本执行的操作)来实现它,但是当我尝试使用脚本时(不是我喜欢做什么)。出于某种原因,静态编译时变量 args 是未知的。我已经尝试this.args
但仍然收到错误。如果我尝试为args(String[] args
)声明一个类型,它就不再接收命令行参数。
当脚本以这种方式静态编译时,有没有办法仍然获取命令行参数?
我在Windows 7上使用带有Java 8的Groovy版本2.4.10。
答案 0 :(得分:2)
执行Groovy类和运行简单脚本有区别。编译器只是将您的脚本包装在main方法中是不正确的,脚本的主体将被复制到run
方法中。
示例:
println(args.length)
将转换为
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
def run() {
println(args.length)
}
static void main(String[] args) {
InvokerHelper.runScript(Main, args)
}
}
由于动态类型,这编译得很好。
现在,如果我们向该类添加@CompileStatic
注释,我们将得到未声明变量的错误。
因此,您必须在类中包装代码才能使用静态编译。
您可以在documentation中阅读有关脚本与课程的更多信息。
答案 1 :(得分:2)
该脚本通过对绑定对象的动态评估来工作。如果要使用静态编译,则需要使用显式形式,将test.groovy脚本更改为以下内容:
String[] args = (String[])binding.getVariable('args')
println args.length
使用已经提供的配置脚本,您会得到一个静态的编译脚本。我测试了以这种方式运行它:
groovyc --configscript config.groovy test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2 3
这将打印3
。
如果您根本不想修改test.groovy,则可以创建一个新的基类:
import groovy.transform.CompileStatic
@CompileStatic
abstract class StaticBase extends Script {
StaticBase() {
}
StaticBase(Binding binding) {
super(binding)
}
String[] getArgs() {
(String[]) getBinding().getVariable("args")
}
}
由于基类具有方法getArgs
,所以当test.groovy引用args时,静态编译器将对该方法进行调用。
groovyc --configscript config.groovy -b StaticBase test.groovy
java -cp .;%GROOVY_HOME%\lib\groovy-2.5.3.jar test 1 2
test.class中的代码具有一个run方法,其代码表示this.println(this.getArgs().length)