美文网首页Groovy专题
Groovy基础语法 - 标识符&字符串

Groovy基础语法 - 标识符&字符串

作者: CXY_XZL | 来源:发表于2022-08-24 17:04 被阅读0次

    1.标识符

    1.1普通标识符

    标识符以字母、美元或下划线开头。它们不能以数字开头。
    字母可以介于以下范围内:

    • “a” 到 “z”(小写 ascii 字母)
    • “A”到“Z”(大写的 ascii 字母)
    • “\u00C0”到“\u00D6”
    • “\u00D8”到“\u00F6”
    • “\u00F8”到“\u00FF”
    • “\u0100”到“\uFFFE”

    然后,以下字符可以包含字母和数字。
    以下是有效标识符的几个示例(此处为变量名称):

    def name
    def item3
    def with_underscore
    def $dollarStart
    

    但以下标识符无效:

    def 3tier
    def a+b
    def a#b
    

    当跟随点时,所有关键字也是有效的标识符:

    foo.as
    foo.assert
    foo.break
    foo.case
    foo.catch
    

    1.2带引号的标识符

    带引号的标识符显示在虚线表达式的点之后。例如,person.name表达式的name可以用 person.'name'person."name"来表示。当某些标识符包含 Java 语言规范禁止的非法字符,但 Groovy 在引用这些字符时允许这些字符时,这一点特别有趣。例如,破折号、空格、感叹号等字符,例如:

    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"  //true
    assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"   //true
    

    Groovy提供了不同的字符串文本。实际上,所有类型的字符串都允许在点之后:

    map.'single quote'
    map."double quote"
    map.'''triple single quote'''
    map."""triple double quote"""
    map./slashy string/
    map.$/dollar slashy string/$
    

    普通字符串和Groovy的GStrings(插值字符串)之间存在差异,因为在后一种情况下,内插值插入到最终字符串中以评估整个标识符:

    def firstname = "Homer"
    map."Simpson-${firstname}" = "Homer Simpson"
    
    assert map.'Simpson-Homer' == "Homer Simpson"  //true
    

    2.字符串

    文本文本以称为字符串的字符串链的形式表示。Groovy允许您实例化 java.lang.String 对象,以及GStrings(groovy.lang.GString),这在其他编程语言中也称为插值字符串。

    2.1单引号字符串

    单引号字符串是一系列用单引号括起来的字符:

    'a single-quoted string'
    

    单引号字符串是普通的java.lang.String,不支持插值。

    2.2字符串连接

    所有 Groovy 字符串都可以与运算符+连接:

    assert 'ab' == 'a' + 'b'  //true
    

    2.3三重单引号字符串

    '''a triple-single-quoted string'''
    

    三重单引号字符串是普通的java.lang.String,不支持插值。

    三重单引号字符串可能跨越多行。字符串的内容可以跨越行边界,而无需将字符串拆分为多个部分,也无需串联或换行符转义字符:

    def aMultilineString = '''line one
    line two
    line three'''
    

    如果代码缩进(例如在类的方法正文中),则字符串将包含缩进的空格。Groovy 开发工具包包含用于使用String#stripIndent()方法去除缩进的方法,以及使用采用分隔符字符来标识要从字符串开头删除的文本的String#stripMargin()方法。

    创建字符串时,如下所示:

    def startingAndEndingWithANewline = '''
    line one
    line two
    line three
    '''
    

    会注意到,生成的字符串包含换行符作为第一个字符。可以通过用反斜杠转义换行符来剥离该字符:

    def strippedFirstNewline = '''\
    line one
    line two
    line three
    '''
    
    assert !strippedFirstNewline.startsWith('\n')  //true
    

    2.3双引号字符串

    双引号字符串是一系列用双引号括起来的字符:

    "a double-quoted string"
    

    如果没有java.lang.String内插表达式,双引号字符串是纯文本的,但如果存在groovy.lang.GString内插,则为实例。
    要转义双引号,可以使用反斜杠字符:“双引号:\”。

    2.3.1字符串插值

    任何 Groovy 表达式都可以在所有字符串文本中进行插值,单引号和三重单引号字符串除外。插值是在计算字符串时将字符串中的占位符替换为其值的操作。占位符表达式由 ${}包围。对于明确的虚线表达式,可以省略大括号,即在这些情况下我们可以只使用$ 前缀。如果将 GString 传递给采用 String 的方法,则占位符内的表达式值将计算为其字符串表示形式(通过调用toString()该表达式),并将生成的 String 传递给该方法。
    在这里,我们有一个字符串,其中包含一个引用局部变量的占位符:

    def name = 'Guillaume' // a plain string
    def greeting = "Hello ${name}"
    
    assert greeting.toString() == 'Hello Guillaume'  //true
    

    任何Groovy表达式都是有效的,正如我们在这个例子中看到的算术表达式:

    def sum = "The sum of 2 and 3 equals ${2 + 3}"
    assert sum.toString() == 'The sum of 2 and 3 equals 5'  //true
    

    不仅允许在${}占位符之间使用表达式,而且语句也允许使用。但是,语句的值只是null 。因此,如果在该占位符中插入了多个语句,则最后一个语句应以某种方式返回要插入的有意义的值。例如,“1 和 2 之和等于 ${def a = 1;def b = 2;a + b}“受支持并按预期工作,但一个好的做法通常是坚持使用 GString 占位符内的简单表达式。

    除了${}占位符之外,我们还可以使用一个单独的符号$作为虚线表达式的前缀:

    def person = [name: 'Guillaume', age: 36]
    assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'  //true
    

    但只有 a.ba.b.c等形式的虚线表达式 才有效。包含括号(如方法调用)、闭包的大括号、不属于属性表达式的点或算术运算符的表达式将无效。给定以下数字的变量定义:

    def number = 3.14
    

    以下语句将抛出一个groovy.lang.MissingPropertyException,因为Groovy认为您正在尝试访问该数字的toString属性,该属性不存在。
    同样,如果表达式不明确,则需要保留大括号:

    String thing = 'treasure'
    assert 'The x-coordinate of the treasure is represented by treasure.x' ==
        "The x-coordinate of the $thing is represented by $thing.x"   // <= Not allowed: ambiguous!!
    assert 'The x-coordinate of the treasure is represented by treasure.x' ==
            "The x-coordinate of the $thing is represented by ${thing}.x"  // <= Curly braces required
    

    如果需要转义 GString 中的 ${}$占位符,以便它们按原样显示而不进行插值,则只需使用反斜杠字符来转义美元符号:

    assert '$5' == "\$5"
    assert '${name}' == "\${name}"
    

    2.3.2插值闭包表达式的特殊情况

    到目前为止,我们已经看到我们可以在${}占位符内插入任意表达式,但是闭包表达式有一个${→}表示法。当占位符包含箭头时,表达式实际上是一个闭包表达式 — 您可以将其视为前面有一个美元前缀的闭包:

    def sParameterLessClosure = "1 + 2 == ${-> 3}" 
    assert sParameterLessClosure == '1 + 2 == 3'  //true
    
    def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" 
    assert sOneParamClosure == '1 + 2 == 3'   //true
    

    闭包是一个无参数的闭包,它不接受参数
    此处,闭包采用单个java.io.StringWriter参数,您可以使用<< leftShift 运算符向其追加内容。在任一情况下,两个占位符都是嵌入式闭包。

    从外观上看,它看起来像是定义要插值的表达式的一种更冗长的方式,但与单纯表达式相比,闭包具有一个有趣的优势:惰性求值。

    让我们考虑以下示例:

    def number = 1 
    def eagerGString = "value == ${number}"
    def lazyGString = "value == ${ -> number }"
    
    assert eagerGString == "value == 1"   //true
    assert lazyGString ==  "value == 1"     //true
    
    number = 2 
    assert eagerGString == "value == 1"    //true
    assert lazyGString ==  "value == 2"      //true
    

    2.3.3与java的互操作性

    当一个方法(无论是在Java还是Groovy中实现)需要一个java.lang.String,但是我们传递一个groovy.lang.GString实例时,GString的方法会自动透明地调用toString()

    String takeString(String message) {         
        assert message instanceof String        
        return message
    }
    
    def message = "The message is ${'hello'}"   
    assert message instanceof GString           //true
    
    def result = takeString(message)            
    assert result instanceof String                //true
    assert result == 'The message is hello'    //true
    
    • 我们创建一个 GString 变量
    • 我们仔细检查它是否是 GString 的一个实例
    • 然后,我们将该 GString 传递给一个将 String 作为参数的方法。
    • taskString()该方法的签名明确表示其唯一参数是 String
    • 我们还验证该参数确实是字符串而不是 GString。

    2.3.4GString & String hashCodes

    虽然可以使用内插字符串来代替普通的Java字符串,但它们与字符串在特定方面有所不同:它们的哈希码是不同的。普通 Java 字符串是不可变的,而生成的 GString 字符串表示形式可能会有所不同,具体取决于其内插值。即使对于相同的结果字符串,GStrings 和 Strings 也不具有相同的哈希代码。

    assert "one: ${1}".hashCode() != "one: 1".hashCode() //fasle
    

    应该避免使用GString作为Map键的具有不同哈希值的GString和字符串,特别是当我们尝试检索具有字符串而不是GString的关联值时。

    def key = "a"
    def m = ["${key}": "letter ${key}"]     
    
    assert m["a"] == null //true
    
    • 使用初始对创建映射,其键为 GString
    • 当我们尝试使用 String 键获取值时,我们将找不到它,因为 Strings 和 GString 具有不同的哈希值

    2.4三重双引号字符串

    三重双引号字符串的行为类似于双引号字符串,此外,它们是多行的,就像三重单引号字符串一样。

    def name = 'Groovy'
    def template = """
        Dear Mr ${name},
    
        You're the winner of the lottery!
    
        Yours sincerly,
    
        Dave
    """
    
    assert template.toString().contains('Groovy')  //true
    

    双引号和单引号都不需要在三重双引号字符串中转义。

    2.4.1转义特殊字符

    您可以使用反斜杠字符转义单引号,以避免终止字符串文本:

    'an escaped single quote: \' needs a backslash'
    

    您可以使用双反斜杠转义转义字符本身:

    'an escaped escape character: \\ needs a double backslash'
    

    一些特殊字符还使用反斜杠作为转义字符:


    转义字符.png

    2.4.2统一码转义序列

    对于键盘上不存在的字符,可以使用 unicode 转义序列:反斜杠,后跟“u”,然后是 4 个十六进制数字。

    例如,欧元货币符号可以用以下方式表示:

    'The Euro currency symbol: \u20AC'
    

    2.5斜线

    除了通常的带引号的字符串之外,Groovy还提供斜杠字符串,用作开始和结束分隔符。斜杠字符串对于定义正则表达式和模式特别有用,因为不需要转义反斜杠
    斜杠字符串的示例:

    def fooPattern = /.*foo.*/
    assert fooPattern == '.*foo.*'  //true
    

    只有正斜杠需要用反斜杠进行转义:

    def escapeSlash = /The character \/ is a forward slash/
    assert escapeSlash == 'The character / is a forward slash'  //true
    

    斜线字符串是多行的:

    def multilineSlashy = /one
        two
        three/
    
    assert multilineSlashy.contains('\n')
    

    斜杠字符串可以被认为是定义GString的另一种方式,但具有不同的转义规则。因此,它们支持插值:

    def color = 'blue'
    def interpolatedSlashy = /a ${color} car/
    
    assert interpolatedSlashy == 'a blue car'  //true
    

    2.5.1特殊情况

    空斜杠字符串不能用双正斜杠表示,因为Groovy解析器将其理解为行注释。这就是为什么下面的断言实际上不会编译,因为它看起来像一个非终止语句:

    assert '' == //     //compilation error
    

    由于斜杠字符串主要是为了让正则表达式更容易而设计的,因此GStrings中的一些错误就像$()$5将适用于斜杠字符串。
    请记住,转义反斜杠不是必需的。另一种思考方式是,实际上不支持逃避。斜杠字符串/\t/将不包含制表符,而是包含后跟字符“t”的反斜杠。仅允许斜杠字符转义,即 /\/folder/将是一个包含 '/folder'的斜杠字符串。斜杠转义的结果是斜杠字符串不能以反斜杠结尾。否则,这将转义斜杠字符串终止符。您可以改用一个特殊的技巧./ends with slash ${'\'}/,但最好避免在这种情况下使用斜杠字符串。

    2.6美元斜线

    美元斜线字符串是多行GStrings,用$/开口和/$结束分隔。转义字符是美元符号,它可以转义另一美元或正斜杠。只有在与特殊使用发生冲突时才需要转义美元和正斜杠字符。这些字符通常表示GString占位符,因此$foo可以通过转义美元将这四个字符输入到美元斜杠字符串中,即$$foo.同样,如果您希望一个美元斜杠的收尾分隔符出现在字符串中,则需要对其进行转义。
    以下是一些示例:

    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 opening dollar slashy
        $/$$ escaped closing dollar slashy
    /$
    
    assert [
        'Guillaume',
        'April, 1st',
        '$ dollar sign',
        '$ escaped dollar sign',
        '\\ backslash',
        '/ forward slash',
        '/ escaped forward slash',
        '$/ escaped opening dollar slashy',
        '/$ escaped closing dollar slashy'
    ].every { dollarSlashy.contains(it) }   //all true
    

    它的创建是为了克服斜杠字符串转义规则的一些限制。当它的转义规则适合您的字符串内容时使用它(通常,如果它有一些您不想转义的斜杠)。


    2.7字符串汇总表

    汇总表.png

    2.8字符

    与Java不同,Groovy没有明确的字符文字。但是,您可以通过三种不同的方式明确地使Groovy字符串成为实际字符:

    char c1 = 'A' 
    assert c1 instanceof Character  //true
    
    def c2 = 'B' as char 
    assert c2 instanceof Character   //true
    
    def c3 = (char)'C' 
    assert c3 instanceof Character   //true
    

    相关文章

      网友评论

        本文标题:Groovy基础语法 - 标识符&字符串

        本文链接:https://www.haomeiwen.com/subject/frqogrtx.html