【问题标题】:Compile groovy script statically with command line arguments使用命令行参数静态编译 groovy 脚本
【发布时间】:2017-12-16 17:18:29
【问题描述】:

我正在尝试静态编译一个 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) 声明一个类型,它将不再接收命令行参数。

当脚本以这种方式静态编译时,有没有办法仍然获取命令行参数?

我在带有 Java 8 的 Windows 7 上使用 Groovy 版本 2.4.10。

【问题讨论】:

    标签: groovy compilation command-line-arguments


    【解决方案1】:

    脚本通过绑定对象的动态评估来工作。如果要使用静态编译,则需要使用显式形式,将 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)

    【讨论】:

      【解决方案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 中阅读有关脚本与类的更多信息。

      【讨论】:

      • 我不知道我是怎么错过的。我到处寻找编译器添加的确切样板,但似乎找不到它(除了说明它确实会生成这样的样板)。我不止一次地看了那份文件,不知何故一定是忽略了那部分。看着那,很明显为什么这不起作用也不起作用。
      • 我认为这段代码行不通。你传递参数的语法是什么?
      猜你喜欢
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-14
      • 2010-10-27
      • 2015-12-19
      • 2018-02-05
      相关资源
      最近更新 更多