Groory语言关于省略的知识点

23 篇文章 2 订阅
1 篇文章 0 订阅

【原文:Style guide】

样式指南
开始探索 Groovy 的 Java 开发人员始终摆脱不了 Java 的思维方式,这将逐步影响学习 Groovy,下面一个个特性,指导你提高开发效率并编写更地道的 Groovy 代码。 本文档的目的是指导这样的开发人员,教授一些常见的 Groovy 语法风格、新操作符和新功能(如闭包等)。本指南并不完整,仅作为快速介绍和进一步指南部分的基础 您是否愿意为文档做出贡献并对其进行改进。

1. 没有分号

如果你有 C / C++ / C# / Java 语言开发经验,一定已经习惯了分号,所以我们把它们放在任何地方。 虽然 Groovy 支持 99% 的 Java 语法,有时将一些 Java 代码粘贴到 Groovy 程序中非常容易,结果到处都是大量的分号。 但是… 分号在 Groovy 中是可选的,我们可以省略,删除分号是更地道的。

2. 返回关键字可选

在 Groovy 中,可以返回在方法体中计算的最后一个表达式,而无需 return 关键字。 特别是对于短方法和闭包,为了简洁起见,最好省略它:

String toString() { return "a server" }
String toString() { "a server" }

但有时,当你使用变量时,这看起来不太好,并且在两行上两次直观地看到它:

def props() {
    def m1 = [a: 1, b: 2]
    m2 = m1.findAll { k, v -> v % 2 == 0 }
    m2.c = 3
    m2
}

在这种情况下,在最后一个表达式之前放置一个换行符,或者显式使用 return 可能会产生更好的可读性。

就我自己而言,有时使用 return 关键字,有时不使用,这通常是一个品味问题。 但是,例如,在闭包内部,我们经常省略它。 因此,即使关键字是可选的,如果你认为它阻碍了代码的可读性,也绝不是强制不使用它。

但请注意一点。 当使用使用 def 关键字而不是特定具体类型定义的方法时,您可能会惊讶地看到有时会返回最后一个表达式。 所以通常更喜欢使用特定的返回类型,如 void 或类型。 在上面的示例中,假设我们忘记将 m2 作为要返回的最后一条语句,最后一个表达式将是 m2.c = 3,这将返回…3,而不是您期望的结果。

if/elsetry/catch 这样的语句也可以返回一个值,因为在这些语句中计算了“最后一个表达式”:

def foo(n) {
    if(n == 1) {
        "Roshan"
    } else {
        "Dawrani"
    }
}

assert foo(1) == "Roshan"
assert foo(2) == "Dawrani"

3. Def 和 type(定义和类型)

当我们谈论 def 和类型时,我经常看到开发人员同时使用 def 和类型。 但是 def 在这里是多余的。 所以做出选择,要么使用 def 要么使用类型。

所以不要写:

def String name = "Guillaume"

要写成这样:

String name = "Guillaume"
// 或者写成这样
def name = "Guillaume"

在 Groovy 中使用 def 时,实际的类型持有者是 Object(因此您可以将任何对象分配给用 def 定义的变量,如果声明方法返回 def,则返回任何类型的对象)。

定义带有无类型参数的方法时,您可以使用 def 但它不是必需的,因此我们倾向于省略它们。 所以而不是:

void doSomething(def param1, def param2) { }

这样写更好:

void doSomething(param1, param2) { }

但正如我们在文档的最后一节中提到的,通常最好输入方法参数,来帮助记录代码,并帮助 IDE 完成代码,或利用静态类型检查或静态编译功能 Groovy 的。

def 多余且应避免的另一个地方是在定义构造函数时:

class MyClass {
    def MyClass() {}
}

相反,只需删除 def

class MyClass {
    MyClass() {}
}

4. 默认公开

默认情况下,Groovy 将类和方法视为公共的。 所以你不必在任何公共的地方都使用 public 修饰符。 只有当它不公开时,你才应该放置一个可见性修饰符。

所以不是:

public class Server {
    public String toString() { return "a server" }
}

喜欢更简洁的:

class Server {
    String toString() { "a server" }
}

您可能想知道 package-scope 的可见性,Groovy 允许省略 public 的事实意味着默认情况下不支持此范围,但实际上有一个特殊的 Groovy 注释允许您使用该可见性:

class Server {
    @PackageScope Cluster cluster
}

5. 省略括号

Groovy 允许您省略顶级表达式的括号,例如 println 命令:

println "Hello"
method a, b

对比:

println("Hello")
method(a, b)

当闭包是方法调用的最后一个参数时,例如使用 Groovy 的 each{} 迭代时,您可以将闭包放在右括号外面,甚至可以省略括号:

list.each( { println it } )
list.each(){ println it }
list.each  { println it }

总是更喜欢第三种形式,它更自然,因为一对空括号只是无用的语法噪音!

在某些情况下需要括号,例如进行嵌套方法调用或调用不带参数的方法时。

def foo(n) { n }
def bar() { 1 }

println foo 1 // won't work
def m = bar   // won't work

6. Classes as first-class citizens(作为一等公民的阶级??)

Groovy 中不需要 .class 后缀,有点像 Java 的 instanceof

例如:

connection.doPost(BASE_URI + "/modify.hqu", params, ResourcesResponse.class)

使用 GStrings 我们将在下面介绍,并使用一等公民(??):

connection.doPost("${BASE_URI}/modify.hqu", params, ResourcesResponse)

7. Getters 和 Setters 方法

在 Groovy 中,getter 和 setter 构成了我们所说的“属性”,并提供了访问和设置这些属性的快捷方式。 因此,您可以使用类似字段的访问表示法,而不是用Java 的方式调用 getter/setter :

resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME

resourcePrototype.setName("something")
resourcePrototype.name = "something"

在 Groovy 中编写 bean 时,通常称为 POGO(Plain Old Groovy Objects),您不必自己创建字段和 getter/setter,而是让 Groovy 编译器为您完成。

所以不是:

class Person {
    private String name
    String getName() { return name }
    void setName(String name) { this.name = name }
}

你可以简单地写:

class Person {
    String name
}

如您所见,没有修饰符可见性的独立“field”实际上使 Groovy 编译器为您生成私有字段以及 getter 和 setter。

当使用 Java 中的此类 POGO 时,getter 和 setter 确实存在,当然可以照常使用。

尽管编译器会创建通常的 getter/setter 逻辑,但如果您希望在这些 getter/setter 中执行任何其他或不同的操作,您仍然可以自由提供它们,并且编译器将使用您的逻辑,而不是默认生成的逻辑。

8. 使用命名参数和默认构造函数初始化 bean

像这样的 bean :

class Server {
    String name
    Cluster cluster
}

而不是在后续语句中设置每个 setter,如下所示:

def server = new Server()
server.name = "Obelix"
server.cluster = aCluster

你可以将命名参数与默认构造函数一起使用(首先调用构造函数,然后按照它们在映射中指定的顺序调用 setter):

def server = new Server(name: "Obelix", cluster: aCluster)

9. 使用 with() 和 tap() 对同一个 bean 进行重复操作

Named-parameters with the default constructor is interesting when creating new instances, but what if you are updating an instance that was given to you, do you have to repeat the ‘server’ prefix again and again? No, thanks to the with() and tap() methods that Groovy adds on all objects of any kind:
创建新实例时,带有默认构造函数的命名参数很有趣,但是如果你要更新提供给你的实例,你是否必须一次又一次地重复“server”前缀呢? 不,感谢 Groovy 添加在任何类型的所有对象上的 with() 和 tap() 方法:

server.name = application.name
server.status = status
server.sessionCount = 3
server.start()
server.stop()

对比:

server.with {
    name = application.name
    status = status
    sessionCount = 3
    start()
    stop()
}

与 Groovy 中的任何闭包一样,最后一条语句被视为返回值。 在上面的例子中,这是 stop() 的结果。 要将其用作仅返回传入对象的构建器,还有 tap():

def person = new Person().with {
    name = "Ada Lovelace"
    it // Note the explicit mention of it as the return value
}

对比:

def person = new Person().tap {
    name = "Ada Lovelace"
}

注意:您也可以使用 with(true) 代替 tap() 和 with(false) 代替 with()。

10. Equals 和 ==

Java 的 == 实际上是 Groovy 的 is() 方法,而 Groovy 的 == 是一个更聪明的 equals()

要比较对象的引用,您应该使用 a.is(b) 而不是 ==

但是要进行通常的 equals() 比较,您应该更喜欢 Groovy 的 ==,因为它也可以避免 NullPointerException,而与 left 或 right 是否为 null 无关。

不是:

status != null && status.equals(ControlConstants.STATUS_COMPLETED)

而是:

status == ControlConstants.STATUS_COMPLETED

11. GStrings (interpolation, multiline)

我们经常在 Java 中使用字符串和变量连接,其中有许多双引号、加号和 \n 字符的开/关作为换行符。 使用内插字符串(称为 GStrings),这样的字符串看起来更好,而且输入起来也不那么痛苦:

throw new Exception("Unable to convert resource: " + resource)

对比:

throw new Exception("Unable to convert resource: ${resource}")

在花括号内,您可以放置任何类型的表达式,而不仅仅是变量。 对于简单的变量,或者 variable.property,你甚至可以去掉花括号:

throw new Exception("Unable to convert resource: $resource")

您甚至可以使用带有 ${-> resource } 的闭包符号懒惰地评估这些表达式。 当 GString 将被强制转换为 String 时,它将评估闭包并获得返回值的 toString() 表示。

例子:

int i = 3

def s1 = "i's value is: ${i}"
def s2 = "i's value is: ${-> i}"

i++

assert s1 == "i's value is: 3" // eagerly evaluated, takes the value on creation
assert s2 == "i's value is: 4" // lazily evaluated, takes the new value into account

当字符串及其连接的表达式在 Java 中很长时:

throw new PluginException("Failed to execute command list-applications:" +
    " The group with name " +
    parameterMap.groupname[0] +
    " is not compatible group of type " +
    SERVER_TYPE_NAME)

您可以使用 \ 继续拼接字符(这不是多行字符串):

throw new PluginException("Failed to execute command list-applications: \
The group with name ${parameterMap.groupname[0]} \
is not compatible group of type ${SERVER_TYPE_NAME}")

或者使用带三重引号的多行字符串:

throw new PluginException("""Failed to execute command list-applications:
    The group with name ${parameterMap.groupname[0]}
    is not compatible group of type ${SERVER_TYPE_NAME)}""")

你还可以通过对该字符串调用 .stripIndent() 来去除出现在多行字符串左侧的缩进。

还要注意 Groovy 中单引号和双引号之间的区别:单引号始终创建 Java 字符串,而无需插入变量,而双引号在存在插入变量时创建 Java 字符串或 GString。

对于多行字符串,您可以使用三重引号:即 GString 的三重双引号和纯字符串的三重单引号。

如果你需要编写正则表达式模式,应该使用“斜线”字符串表示法:

assert "foooo/baaaaar" ==~ /fo+\/ba+r/

“斜线”符号的优点是您不需要双重转义反斜线,使使用正则表达式更简单一些。

最后但并非最不重要的一点是,当您需要字符串常量时更喜欢使用单引号字符串,当您明确依赖字符串插值时使用双引号字符串。

12. 数据结构的原生语法

Groovy 为数据结构(如lists, maps, regex, 或ranges范围)提供原生语法构造。 确保在您的 Groovy 程序中利用它们。

以下是这些原生结构的一些示例:

def list = [1, 4, 6, 9]

// by default, keys are Strings, no need to quote them
// you can wrap keys with () like [(variableStateAcronym): stateName] to insert a variable or object as a key.
def map = [CA: 'California', MI: 'Michigan']

// ranges can be inclusive and exclusive
def range = 10..20 // inclusive
assert range.size() == 11
// use brackets if you need to call a method on a range definition
assert (10..<20).size() == 10 // exclusive

def pattern = ~/fo*/

// equivalent to add()
list << 5

// call contains()
assert 4 in list
assert 5 in list
assert 15 in range

// subscript notation
assert list[1] == 4

// add a new key value pair
map << [WA: 'Washington']
// subscript notation
assert map['CA'] == 'California'
// property notation
assert map.WA == 'Washington'

// matches() strings against patterns
assert 'foo' ==~ pattern

13. Groovy 开发工具包

继续介绍数据结构,当您需要迭代集合时,Groovy 提供了各种额外的方法,修饰 Java 的核心数据结构,例如 each{}、find{}、findAll{}、every{}、collect{}、inject{} ,这些方法为编程语言添加了函数式风格,并有助于更轻松地处理复杂的算法。 由于语言的动态特性,许多新方法通过装饰应用于各种类型。 您可以在String, Files, Streams, Collections等方面找到许多非常有用的方法:

http://groovy-lang.org/gdk.html

14. 超强switch

Groovy 的 switch 比通常只能接受原语和同化的 C 语言强大得多。 Groovy 的 switch 几乎可以接受任何类型。

def x = 1.23
def result = ""
switch (x) {
    case "foo": result = "found foo"
    // lets fall through
    case "bar": result += "bar"
    case [4, 5, 6, 'inList']:
        result = "list"
        break
    case 12..30:
        result = "range"
        break
    case Integer:
        result = "integer"
        break
    case Number:
        result = "number"
        break
    case { it > 3 }:
        result = "number > 3"
        break
    default: result = "default"
}
assert result == "number"

通常来讲,带有 isCase() 方法的类型也可以决定一个值是否与一个 case 对应

15. 导入别名

在 Java 中,当使用同名但来自不同包的两个类(如 java.util.Listjava.awt.List)时,您可以导入一个类,但必须对另一个使用完全限定的名称。

有时,在您的代码中,长类名的多次使用会增加代码的冗长性并降低代码的清晰度。

为了改善这种情况,Groovy 提供了导入别名:

import java.util.List as UtilList
import java.awt.List as AwtList
import javax.swing.WindowConstants as WC

UtilList list1 = [WC.EXIT_ON_CLOSE]
assert list1.size() instanceof Integer
def list2 = new AwtList()
assert list2.size() instanceof java.awt.Dimension

还可以在静态导入方法时使用别名:

import static java.lang.Math.abs as mabs
assert mabs(-4) == 4

16. Groovy 的真假

所有对象都可以“强制”为布尔值:所有为 null、void、等于 0 或为空的都计算为 false,如果不是,则计算为 true。

所以而不是写:

if (name != null && name.length > 0) {}

可以这样写:

if (name) {}

collections等也是如此。

因此,可以在 while()、if()、三元运算符、Elvis 运算符(见下文)等中使用一些快捷方式。

甚至可以通过向类中添加布尔 asBoolean() 方法来自定义 Groovy Truth!

17. 安全的图形导航

Groovy 支持 . 操作符来安全地导航对象图。

在 Java 中,当您对图中的某个节点感兴趣并需要检查是否为 null 时,您通常最终会编写复杂的 if 或嵌套 if 语句,如下所示:

if (order != null) {
    if (order.getCustomer() != null) {
        if (order.getCustomer().getAddress() != null) {
            System.out.println(order.getCustomer().getAddress());
        }
    }
}

. 操作符安全解除引用运算符,可以使用以下方法简化此类代码:

println order?.customer?.address

在整个调用链中检查空值,如果任何元素为空,则不会抛出 NullPointerException,如果某项为空,则结果值将为空。

18. Assert

要检查参数、返回值等,您可以使用 assert 语句。

与 Java 的 assert 相反,asserts 不需要激活即可工作,因此始终检查 asserts。

def check(String name) {
    // name non-null and non-empty according to Groovy Truth
    assert name
    // safe navigation + Groovy Truth to check
    assert name?.size() > 3
}

你还会注意到 Groovy 的“Power Assert”语句提供的不错的输出,以及每个被断言的子表达式的各种值的图形视图。

19. 默认值的 Elvis 运算符

Elvis 运算符是一种特殊的三元运算符快捷方式,可方便地用于默认值。

我们经常不得不写这样的代码:

def result = name != null ? name : "Unknown"

感谢 Groovy 真假判断,空检查可以简化为“name”。

更进一步,因为无论如何你都会返回 ‘name’,而不是在这个三元表达式中重复 name 两次,我们可以通过使用 Elvis 运算符以某种方式删除问号和冒号之间的内容,这样上面的内容就变成了:

def result = name ?: "Unknown"

20. 捕捉任何异常

如果你真的不关心在你的 try 块中抛出的异常的类型,你可以简单地捕获它们中的任何一个,并简单地忽略捕获的异常的类型。 所以,不是像这样捕捉异常:

try {
    // ...
} catch (Exception t) {
    // something bad happens
}

然后捕捉任何东西(‘any’ 或 ‘all’,或者任何让你认为它是任何东西的东西):

try {
    // ...
} catch (any) {
    // something bad happens
}

请注意,它正在捕获所有异常,而不是 Throwable。 如果你真的需要捕捉“一切”,你必须明确并说你想要捕捉Throwables。

21. 建议

我将完成一些关于何时以及如何使用可选输入的词。 Groovy 让您决定是使用显式强类型,还是何时使用 def

我有一个相当简单的经验法则:每当您编写的代码将被其他人用作公共 API 时,您应该始终支持使用强类型,它有助于使合同更强大,避免可能通过参数类型错误,提供更好的文档,还有助于 IDE 完成代码。 每当代码仅供您使用时,例如私有方法,或者当 IDE 可以轻松推断类型时,您就可以更自由地决定何时键入或不键入。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,关于英语省略句,以下是一些知识点: 1. 主语和动词的省略:在一个句子中,如果主语和动词都已经在上下文中被提到过了,那么在后面的从句或者句子中可以将它们省略掉。比如:I am going to the store. Would you like to come with me? 这里的第二个句子中省略了主语和动词,完整的句子应该是 "Would you like to come with me (to the store)?" 2. 宾语的省略:如果一个句子中主语和谓语已经表明了对什么事物或者什么人物进行了什么动作,那么后面的宾语可以省略掉。比如:She loves coffee, and he tea. 这里第二个句子中省略了宾语,完整的句子应该是 "he loves tea." 3. 状语的省略:在句子中,如果某些状语已经从上下文中得到了说明,那么这些状语在后面的句子中可以省略。比如:John went to bed early because he was tired. He slept until noon. 这里第二个句子中省略了状语,完整的句子应该是 "He slept until noon (because he went to bed early)." 希望这些知识点能够帮到您! ### 回答2: 关于英语省略句的方法,共有几个知识点需要注意。 首先,名词的省略。在英语中,当句子中已经有名词出现过,后续的同类名词可以省略。例如,"I have a pen, and she has a pen too." 句子中的第二个"pen"可以省略,变成"I have a pen, and she has one too." 其次,动词的省略。在一些特定的情况下,主语和谓语之间的动词可以省略。例如,"John is studying English. (John is) a diligent student." 句子中的第二个动词"is"可以省略,因为前后两个句子的主语都是"John"。 另外,定语的省略也是一种常见的省略句现象。在描述物品或人的特征时,定语可以被省略。例如,"She has a book (that is) red." 句子中的"that is"可以省略,因为它只是对前面的书进行更详细的描述。 最后,冠词的省略也是常见的省略句情况之一。在某些情况下,冠词可以被省略。例如,"I want to buy (a) new car." 句子中的"a"可以省略,这样句子仍然可以传达出想买一辆新车的意思。 总之,了解英语省略句的方法对于理解和运用英语语法非常重要。需要注意不同种类的省略情况,并灵活运用在实际语境中。同时,对于有时省略可能带来的困惑或歧义,也要适度添加信息以保持语句的准确性和清晰度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值