Groovy 官方文档翻译 - 01 - 语法
1.注释
1.1.单行注释
// a standalone single line comment
println "hello"// a comment till the end of the line
1.2.多行注释
/* a standalone multiline comment
spanning two lines */
println "hello"/* a multiline comment starting
at the end of a statement */
println 1/* one */+2/* two */
1.3.GroovyDoc
/**
* A Class description
*/
class Person {
/** the name of the person */
String name
/**
* Creates a greeting method for a certain person.
*
* @param otherPerson the person to greet
* @return a greeting message
*/
String greet(String otherPerson) {
"Hello ${otherPerson}"
}
}
1.4.Shebang line
#!/usr/bin/env groovy
println "Hello from the shebang line"
2.关键字
Groovy 中的所有关键字:
- | - | - | - | - | |
---|---|---|---|---|---|
as |
assert |
break |
case |
catch |
|
class |
const |
continue |
def |
default |
|
do |
else |
enum |
extends |
false |
|
finally |
for |
goto |
if |
implements |
|
import |
in |
instanceof |
interface |
new |
|
null |
package |
return |
super |
switch |
|
this |
throw |
throws |
trait |
true |
|
try |
while |
3.标识符
3.1.普通标识符
标识符第一个字符可以是字母、美元符号或者下划线,但是不能是数字。后面可以跟随字母和数字。下面是合法的标识符:
def name
def item3
def with_underscore
def $dollarStart
下面是无效地标识符
def3tierdef a+b
def a#b
点号后面可以使用和关键字相同的标识符(最好别这样使用)
foo.as
foo.assert
foo.break
foo.case
foo.catch
3.2.引号标识符
将标识符放在引号中,就可以使用一些特殊字符了
def map =[:]
map."an identifier with a space and double quotes"="ALLOWED"
map.'with-dash-signs-and-single-quotes'="ALLOWED"
assert map."an identifier with a space and double quotes"=="ALLOWED"
assert map.'with-dash-signs-and-single-quotes'=="ALLOWED"
Groovy 中的几种字符串都可以作为引号标识符
map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$
GString 也可以作为引号标识符,非常动态
def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"
assert map.'Simson-Homer' == "Homer Simson"
4.字符串
Groovy 中有两种字符串
- 普通字符串
java.lang.String
- 插值字符串
groovy.lang.GString
4.1.单引号字符串
单引号字符串就是普通字符串 java.lang.String
'a single quoted string'
4.2.字符串连接
使用 +
连接字符串
assert 'ab' == 'a' + 'b'
4.3.三个单引号字符串
三个单引号字符串也是普通字符串 java.lang.String
,不支持插值
'''a triple single quoted string'''
三个单引号字符串可以使多行文本,并保留文本格式
def aMultilineString = '''line one
line two
line three'''
字符串有两个方法可以处理其中的缩进和留边
String#stripIndent()
String#stripMargin()
下面这样创建三引号字符串,第一个字符会是一个换行符
def startingAndEndingWithANewline = '''
line one
line two
line three
'''
可以用反斜杠可以去掉这个换行符
def strippedFirstNewline = '''\
line one
line two
line three
'''
assert !strippedFirstNewline.startsWith('\n')
4.3.1.转义字符
转义符 | 说明 |
---|---|
'\t' | 制表符 |
'\b' | 退格符 |
'\n' | 换行符 |
'\r' | 回车符 |
'\f' | formfeed |
'\\' | 反斜杠 |
''' | 单引号 |
'"' | 双引号 |
4.3.2.Unicode 转义序列
一些键盘上没有的字符可以用 Unicode 码进行转义,反斜杠加上小写字母 u
再加 Unicode
码即可
'The Euro currency symbol: \u20AC'
4.4. 双引号字符串
双引号字符串中如果没有出现插值表达式,则就是普通的 java.lang.String
;如果出现了插值表达式,则是 groovy.lang.GString
"a double quoted string"
4.4.1. 插值字符串
有两种插值方法:
-
${}
,花括号里面填入表达式 -
$
后面直接跟点号表达式
最后用 toString()
求值
def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"
assert greeting.toString() == 'Hello Guillaume'
在花括号中,数学表达式也可以使用
def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5'
在花括号中不仅可以使用表达式,也可以使用语句,但是语句没有返回值,因此插值表达式中的最后一条语句应该有个返回值。例如:
"The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}"
最佳实践是尽量使用简洁的表达式。
除了使用花括号表达式,也可以使用点号表达式
def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'
点号表达式只能使用 a.b 或者 a.b.c 这样的形式,不能跟括号或者运算符,例如对于一个普通数字对象:
def number =3.14
下面的表达式就会抛出 groovy.lang.MissingPropertyException
异常, Groovy 会去查找 toString
属性,而不是调用方法,这个属性是不存在的
shouldFail(MissingPropertyException){
println "$number.toString()"
}
代码 "$number.toString()"
实际上被解析成 "${number.toString}()"
.
此外,如果在差值中需要使用美元符号,则用反斜杠转意
assert'${name}'=="\${name}"
4.4.2.闭包插值表达式
使用 ${→}
加入一个闭包插值表达式。闭包表达式只能接受零个或者一个参数,多于一个参数将抛出异常。
- 没有参数的时候,闭包的值就是最后一个表达式的值
- 有一个参数的时候,传入的参数类型为
java.io.StringWriter
,壁报返回值就是这个对象
def sParameterLessClosure = "1 + 2 == ${-> 3}"
assert sParameterLessClosure == '1 + 2 == 3'
def sOneParamClosure = "1 + 2 == ${ w -> w << 3}"
assert sOneParamClosure == '1 + 2 == 3'
因为闭包可以包含外部状态变量,因此使用闭包插值可以惰性求值,例如下面的代码
def number = 1
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"
assert eagerGString == "value == 1"
assert lazyGString == "value == 1"
number = 2
assert eagerGString == "value == 1"
assert lazyGString == "value == 2"
4.4.3.与 Java 的互操作性
当一个方法需要 java.lang.String
,但是传入了一个 groovy.lang.GString
参数的时候,将自动调用 toString()
方法进行转换,如下:
String takeString(String message) {
assert message instanceof String
return message
}
def message = "The message is ${'hello'}"
assert message instanceof GString
def result = takeString(message)
assert result instanceof String
assert result == 'The message is hello'
4.4.4.GString 和 String 的 hashCode
GString
和 String
的 hashCode
是不同的
assert "one: ${1}".hashCode() != "one: 1".hashCode()
String
是不变的,GString
是可变的,因此不能用 GString
作为键值对的键,下面的代码将找不到 m["a"]
,因为二者的 hashCode
不同
def key = "a"
def m = ["${key}": "letter ${key}"]
assert m["a"] == null
4.5.三个双引号字符串
三个双引号字符串和三个单引号字符串基本相同,除了可以差值
def name = 'Groovy'
def template = """
Dear Mr ${name},
You're the winner of the lottery!
Yours sincerly,
Dave
"""
assert template.toString().contains('Groovy')
在三个双引号字符串中,单引号和双引号都不需要转义
4.6. 正则表达式字符串
正则表达式字符串和普通字符串有同样的值
def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'
斜杠需要转义
def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'
也可以是多行的
def multilineSlashy = /one
two
three/
assert multilineSlashy.contains('\n')
可以插值
def color = 'blue'
def interpolatedSlashy = /a ${color} car/
assert interpolatedSlashy == 'a blue car'
没有空正则字符串,因为两个斜杠是注释
assert '' == //
4.7. 多行正则表达式字符串
多行正则表达式字符串用 $/ ..... /$ 括起来,美元符号成为了转义符,但是美元符号和斜杠本身都不用转义,除非你碰到了类似于 GString 占位符,或者多行正则字符串的结尾,这两种字符串需要转义
def name = "Guillaume"
def date = "April, 1st"
def dollarSlashy = $/
Hello $name, //占位符不需要转义
today we're ${date}.
$ dollar sign //美元符号不需要转义
$$ escaped dollar sign //即使转义还是他自己
\ backslash
/ forward slash //斜杠反斜杠都不用转义
$/ escaped forward slash
$/$ escaped dollar slashy string delimiter //结束符要转移
/$
4.8.字符串总结表格
字符串类型 | 语法 | 差值 | 多行 | 转义符 |
---|---|---|---|---|
单引号 | '…' |
\ |
||
三引号 | '''…''' |
Yes |
\ |
|
双引号 | "…" |
Yes |
\ |
|
三个双引号 | """…""" |
Yes |
Yes |
\ |
斜杠 | /…/ |
Yes |
Yes |
\ |
美元加斜杠 | $/…/$ | Yes |
Yes |
$ |
4.9.字符
Groovy 中没有单独的字符类型,可以将字符串类型“显式转换”成字符类型
char c1 = 'A'
assert c1 instanceof Character
def c2 = 'B' as char
assert c2 instanceof Character
def c3 = (char)'C'
assert c3 instanceof Character
5.数字
5.1.整数字面量
和 Java 中一样有以下几种整数:
byte
char
short
-
int
- 如果没有什么类型,这是默认类型 long
java.lang.BigInteger
他们都是原生类型
// primitive types
byte b = 1
char c = 2
short s = 3
int i = 4
long l = 5
// infinite precision
BigInteger bi = 6
def
关键字定义的变量会自动确认整数的长度
def a = 1
assert a instanceof Integer
// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer
// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long
// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long
// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger
负整数也是一样
def na = -1
assert na instanceof Integer
// Integer.MIN_VALUE
def nb = -2147483648
assert nb instanceof Integer
// Integer.MIN_VALUE - 1
def nc = -2147483649
assert nc instanceof Long
// Long.MIN_VALUE
def nd = -9223372036854775808
assert nd instanceof Long
// Long.MIN_VALUE - 1
def ne = -9223372036854775809
assert ne instanceof BigInteger
5.1.1.非 10 进制数
二进制以 0b
开头
int xInt = 0b10101111
assert xInt == 175
short xShort = 0b11001001
assert xShort == 201 as short
byte xByte = 0b11
assert xByte == 3 as byte
long xLong = 0b101101101101
assert xLong == 2925l
BigInteger xBigInteger = 0b111100100001
assert xBigInteger == 3873g
int xNegativeInt = -0b10101111
assert xNegativeInt == -175
八进制以 0
开头
int xInt = 077
assert xInt == 63
short xShort = 011
assert xShort == 9 as short
byte xByte = 032
assert xByte == 26 as byte
long xLong = 0246
assert xLong == 166l
BigInteger xBigInteger = 01111
assert xBigInteger == 585g
int xNegativeInt = -077
assert xNegativeInt == -63
十六进制以 0x
开头
int xInt = 0x77
assert xInt == 119
short xShort = 0xaa
assert xShort == 170 as short
byte xByte = 0x3a
assert xByte == 58 as byte
long xLong = 0xffff
assert xLong == 65535l
BigInteger xBigInteger = 0xaaaa
assert xBigInteger == 43690g
Double xDouble = new Double('0x1.0p0')
assert xDouble == 1.0d
int xNegativeInt = -0x77
assert xNegativeInt == -119
5.2.小数
小数有以下几种类型:
float
double
-
java.lang.BigDecimal
- 如果没有声明类型,这是默认类型
// primitive types
float f = 1.234
double d = 2.345
// infinite precision
BigDecimal bd = 3.456
科学计数法
assert 1e3 == 1_000.0
assert 2E4 == 20_000.0
assert 3e+1 == 30.0
assert 4E-2 == 0.04
assert 5e-1 == 0.5
Groovy 默认使用 BigDecimal 作为小数的类型,要使用另外两种类型需要显式声明
5.3.下划线
可以用下划线分割数字,更容易阅读
long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
5.4.数字后缀
可以用数字后缀表示类型
Type | Suffix |
---|---|
BigInteger | G or g |
Long | L or l |
Integer | I or i |
BigDecimal | G or g |
Double | D or d |
Float | F or f |
Examples:
assert 42I == new Integer('42')
assert 42i == new Integer('42') // lowercase i more readable
assert 123L == new Long("123") // uppercase L more readable
assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')
assert 1.234F == new Float('1.234')
assert 1.23E23D == new Double('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal
5.5.数学运算
除了除法和幂运算以外,不同数据类型经过二元操作符数学运算以后,结果的数据类型如下:
-
byte
,char
,short
和int
之间运算返回int
-
long
和byte
,char
,short
和int
之间运算返回long
-
BigInteger
和任意其他整数类型运算返回BigInteger
-
float
,double
和BigDecimal
之间运算返回double
- 两个
BigDecimal
运算返回BigDecimal
关系表格如下
byte | char | short | int | long | BigInteger | float | double | BigDecimal | |
---|---|---|---|---|---|---|---|---|---|
byte | int | int | int | int | long | BigInteger | double | double | double |
char | int | int | int | long | BigInteger | double | double | double | |
short | int | int | long | BigInteger | double | double | double | ||
int | int | long | BigInteger | double | double | double | |||
long | long | BigInteger | double | double | double | ||||
BigInteger | BigInteger | double | double | double | |||||
float | double | double | double | ||||||
double | double | double | |||||||
BigDecimal | BigDecimal |
5.5.1.除法运算的情况
对于除法运算
- 如果两边操作数都是
float
或者double
类型,则返回double
- 其他类型
( short, char, byte, int, long, BigInteger or BigDecimal)
返回BigDecimal
BigDecimal
的除法运算实际调用了 divide()
方法
和 Java 一样,Groovy 没有整除操作符,需要调用 intdiv()
方法
5.5.2.幂运算的情况
幂运算符 **
其返回值的类型和基与指数有关系:
指数是小数或者负数的情况下:
- 如果结果能表示成
Integer
,则返回Integer
- 如果结果能表示成
Long
,则返回Long
- 否则返回
Double
指数是0
或者负数的情况下:
- 如果底数是
BigDecimal
, 则返回BigDecimal
- 如果底数是
BigInteger
, 则返回BigInteger
- 如果底数是
Integer
, 能装下则返回Integer
,装不下就返回BigInteger
- 如果底数是
Long
, 能装下则返回Long
,装不下就返回BigInteger
// base and exponent are ints and the result can be represented by an Integer
assert 2 ** 3 instanceof Integer // 8
assert 10 ** 9 instanceof Integer // 1_000_000_000
// the base is a long, so fit the result in a Long
// (although it could have fit in an Integer)
assert 5L ** 2 instanceof Long // 25
// the result can't be represented as an Integer or Long, so return a BigInteger
assert 100 ** 10 instanceof BigInteger // 10e20
assert 1234 ** 123 instanceof BigInteger // 170515806212727042875...
// the base is a BigDecimal and the exponent a negative int
// but the result can be represented as an Integer
assert 0.5 ** -2 instanceof Integer // 4
// the base is an int, and the exponent a negative float
// but again, the result can be represented as an Integer
assert 1 ** -0.3f instanceof Integer // 1
// the base is an int, and the exponent a negative int
// but the result will be calculated as a Double
// (both base and exponent are actually converted to doubles)
assert 10 ** -1 instanceof Double // 0.1
// the base is a BigDecimal, and the exponent is an int, so return a BigDecimal
assert 1.2 ** 10 instanceof BigDecimal // 6.1917364224
// the base is a float or double, and the exponent is an int
// but the result can only be represented as a Double value
assert 3.4f ** 5 instanceof Double // 454.35430372146965
assert 5.6d ** 2 instanceof Double // 31.359999999999996
// the exponent is a decimal value
// and the result can only be represented as a Double value
assert 7.8 ** 1.9 instanceof Double // 49.542708423868476
assert 2 ** 0.1f instanceof Double // 1.0717734636432956
6.布尔值
def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true
7.列表
Groovy 的列表实现了 java.util.List
接口,默认为 java.util.ArrayList
类型
def numbers = [1, 2, 3]
assert numbers instanceof List
assert numbers.size() == 3
列表中可以包含不同的数据类型
def arrayList = [1, 2, 3]
assert arrayList instanceof java.util.ArrayList
def linkedList = [2, 3, 4] as LinkedList
assert linkedList instanceof java.util.LinkedList
LinkedList otherLinked = [3, 4, 5]
assert otherLinked instanceof java.util.LinkedList
用 []
加索引访问列表中的元素,索引可以是负值,左移符号 <<
向列表中添加新元素。
也可以一次访问或者设置多个元素
def letters = ['a', 'b', 'c', 'd']
assert letters[0] == 'a'
assert letters[1] == 'b'
assert letters[-1] == 'd'
assert letters[-2] == 'c'
letters[2] = 'C'
assert letters[2] == 'C'
letters << 'e'
assert letters[ 4] == 'e'
assert letters[-1] == 'e'
assert letters[1, 3] == ['b', 'd']
assert letters[2..4] == ['C', 'd', 'e']
多维列表
def multi = [[0, 1], [2, 3]]
assert multi[1][0] == 2
8.数组
Groovy 中数组和列表使用同样的符号,因此数组需要显式声明
String[] arrStr = ['Ananas', 'Banana', 'Kiwi']
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
def numArr = [1, 2, 3] as int[]
assert numArr instanceof int[]
assert numArr.size() == 3
也可以定义多维数组
def matrix3 = new Integer[3][3]
assert matrix3.size() == 3
Integer[][] matrix2
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]
访问数组中的元素和列表同样
String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
assert names[0] == 'Cédric'
names[2] = 'Blackdrag'
assert names[2] == 'Blackdrag'
9.键值对
Groovy 的键值对是 java.util.LinkedHashMap
类型,可以用方括号来访问,也可以用点号来访问。
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000'
assert colors.green == '#00FF00'
colors['pink'] = '#FF00FF'
colors.yellow = '#FFFF00'
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap
如果访问一个不存在的键,则返回 null
assert colors.unknown == null
除了字符串,数字也可以当键
def numbers = [1: 'one', 2: 'two']
assert numbers[1] == 'one'
字符串变量不能作为键
def key = 'name'
def person = [key: 'Guillaume']
assert !person.containsKey('name')
assert person.containsKey('key')
用括号括起来则可以
person = [(key): 'Guillaume']
assert person.containsKey('name')
assert !person.containsKey('key')