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. 插值字符串

有两种插值方法:

  1. ${} ,花括号里面填入表达式
  2. $ 后面直接跟点号表达式

最后用 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

GStringStringhashCode 是不同的

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, shortint 之间运算返回 int
  • longbyte, char, shortint 之间运算返回 long
  • BigInteger 和任意其他整数类型运算返回 BigInteger
  • float, doubleBigDecimal 之间运算返回 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')    

你可能感兴趣的:(Groovy 官方文档翻译 - 01 - 语法)