Overview
本节主要介绍各语言中脚本的实现和运行方式。所谓的脚本是使用一种特定的描述性语言,依据一定的格式编写的可执行文件。通常可以用于执行一些简单的代码。
Java 篇
Java 并不支持脚本
Groovy 篇
Groovy 中脚本后缀名也是 .groovy
创建第一个脚本
新建文件 scriptTest.groovy
,文件内容如下
println("Hello World")
保存文件后在控制台 中执行以下语句
groovy scriptTest.groovy
成功的话可以看到命令行输出 Hello World
字符串。这就是脚本的优点,无需创建类,也无需编写可以 main()
方法就可以直接运行代码。
在类或脚本中执行脚本
Groovy 脚本在编译后实际也会转变为对应的 Java 类,所以上一节的例子在编译后会变成以下的代码
public class scriptTest extends Script {
public scriptTest() {
CallSite[] var1 = $getCallSiteArray();
}
public scriptTest(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, scriptTest.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, "Hello World");
}
}
分析以上代码,可以看到 Groovy 脚本编译后实际是生成了一个继承自 Script 的类。该类有两个构造方法(空构造方法和以 Binding 为参数的构造方法),一个 main() 方法,一个 run() 方法,实际编写的代码其实是被编译到 run() 方法中。所以在其它程序中执行 Groovy 脚本就很容易了,只要 new 一个这个脚本类的实例并执行 run() 方法就可以了。
def scope = new scopeScript()
scope.run()
这里特别要注意的是 Groovy 脚本名可以包含
-
这样的特殊字符,但是这种字符并不符合 Java 的类名规范,所以如果脚本名包含特殊字符时就无法通过以上方被执行代码,所以最简单的避免方式就是脚本名不要用特殊字符。
本地域与绑定域
Groovy 脚本中定义的变量有两种作用域,分别为绑定域 (Binding Scope) 和本地域 (Local Scope)。本地域为脚本中使用 def
定义的动态类型变量或用特定类型定义的静态类型变量。绑定域为没有任何前缀修改的变量。
例
本地域
String hello = "hello"
def world = "world"
绑定域
helloworld = "hello world"
本地域在编译后会被声明为 run() 方法中的临时变量,所以只能被脚本当中的语句调用,无法被脚本中定义的其它方法调用。
绑定域可以通过外部的脚本对象的 binding
属性进行赋值,在编译后会被变为脚本类的成员变量,所以可以被脚本中定义的其它方法调用。
例
编写 scopeScript.groovy
文件,内容如下
package com.bookislife.jgsk.groovy._10_script
//local scope
String hello = "hello"
def world = "world"
//binding scope
helloworld = "hello world"
void otherMethod() {
// Wrong!! 无法访问本地域 hello 和 world
// println hello
// println world
// 可以访问绑定域
println(helloworld)
}
println "${hello} ${world}, ${helloworld}"
// 脚本中定义的方法只能访问绑定域
otherMethod()
编写 Scripts.groovy
类文件,以此来调用 scopeScript.groovy
文件
package com.bookislife.jgsk.groovy._10_script
class Scripts {
public static void main(String[] args) {
// Run Scripts
def scope = new scopeScript()
// Binding Values
scope.binding.hello = "goodbye" // hello is not a binding scope
scope.binding.helloworld = "hello groovy" // helloworld is a binding scope
scope.otherMethod()
}
}
通过以上代码可以看到可以使用 binding
属性为脚本中的绑定域进行赋值,但是无法修改本地域。
Scala 篇
Scala 脚本不会被编译成类文件,所以没有 Groovy 脚本那么强大的功能。
编写脚本
例
编写脚本文件 scriptTest.scala
println(s"Hello World, ${if (args.nonEmpty) args(0) else ""}")
保存文件,在控制台下执行以下代码
scala scriptTest.scala Peter
成功的话会输出 "Hello World, Peter"。
从以上代码可以看到 Scala 脚本中使用默认的数组 args
来存储输入的参数。
在 IDEA 中运行脚本
和 Groovy 不一样,Scala 脚本无法直接在 IDEA 中运行,IDEA 会报无法执行或者运行时报找不到符号。如果希望在 IDEA 中运行的话,需要先进行以下设置:
- 打开 "Run" -> "Edit Configurations"
- 点击左上角的 "+" 号,选择 "Scala Script"
- 输入任意 Name,在 "Script file" 一项中选择要运行的脚本文件
- 在 "Before launch" 一项中删除 "Make" 操作
-
上述完成后就可以运行脚本了
Kotlin 篇
Kotlin 脚本后缀为 .kts
,是 Kotlin 1.0 新增加的功能。
编写脚本
例
编写脚本文件,scriptTest.kts
,内容如下
println("Hello World, ${if (args.isNotEmpty()) args[0] else ""}")
保存后在命令行执行以下代码
kotlinc -script scriptTest.kts Peter
成功的话会输出 "Hello World, Peter"。
同 Scala 一样,Kotlin 脚本也使用数组 args
来存储输入的参数。
Summary
- 除 Java 外都支持脚本,其中 Groovy 的功能最强
- Idea 可以直接运行 Groovy 和 Kotlin 脚本,但不支持直接运行 Scala 脚本
文章源码见 https://github.com/SidneyXu/JGSK 仓库的 _10_script
小节