ZetCode

Groovy 宇宙飞船运算符

最后修改于 2025 年 3 月 20 日

Groovy 中的宇宙飞船运算符 <=> 简化了比较,根据左操作数是否小于、等于或大于右操作数,返回 -1、0 或 1。它非常适合排序和自定义比较,提高了可读性,优于传统方法。本教程将通过示例探讨其用法。

数值比较

宇宙飞船运算符比较两个值,产生一个整数结果,指示它们的相对顺序,使其直观易懂,适合基本检查。

BasicSpaceship.groovy
def a = 5
def b = 8
println a <=> b  // Output: -1
println b <=> a  // Output: 1
println a <=> a  // Output: 0

a <=> b 比较 5 和 8:5 < 8,所以结果是 -1。b <=> a 给出 1 (8 > 5),而 a <=> a 是 0 (5 = 5)。这些结果模仿了 Java 的 compareTo,但运算符的语法更简洁且视觉上更清晰。

按长度对字符串进行排序

宇宙飞船运算符在排序方面表现出色,尤其是在闭包中,它允许根据属性对字符串列表等集合进行自定义排序。

SortByLength.groovy
def words = ['sky', 'water', 'emotion', 'shredder', 
    'anonymous', 'on', 'a', 'copper', 'the', 'elephant']

words.sort { e1, e2 -> e1.length() <=> e2.length() }
println words

words.sort { e1, e2 -> e2.length() <=> e1.length() }
println words

e1.length() <=> e2.length() 按字符串长度升序排序 words:从 "a" (1) 到 "anonymous" (9)。通过 e2.length() <=> e1.length() 反向排序,则按降序排序:从 "anonymous" 到 "a"。运算符的输出 (-1, 0, 1) 控制排序顺序,展示了其在自定义比较中的强大功能。

$ groovy SortByLength.groovy
[a, on, sky, the, water, copper, emotion, shredder, elephant, anonymous]
[anonymous, elephant, shredder, emotion, copper, water, the, sky, on, a]

排序自定义对象

通过宇宙飞船运算符实现 Comparable 接口,可以对自定义对象进行排序,以自然、可重用的方式比较它们的属性。

SortUsers.groovy
class User implements Comparable {
    String fname
    String lname
    String occupation

    User(String fname, String lname, String occupation) {
        this.fname = fname
        this.lname = lname
        this.occupation = occupation
    }

    int compareTo(o) {
        this.lname <=> o.lname
    }

    String toString() {
        "${fname} ${lname} - ${occupation}"
    }
}

def users = [
    new User('John', 'Doe', 'gardener'),
    new User('Roger', 'Roe', 'driver'),
    new User('Lucia', 'Smith', 'accountant'),
    new User('Paul', 'Newman', 'firefighter'),
    new User('Adam', 'Clapton', 'teacher'),
    new User('Jane', 'Walter', 'pilot')
]

println users
println users.sort()

User 类在 compareTo 方法中使用 this.lname <=> o.lname 来按姓氏排序。sort() 方法按字母顺序对 users 进行排序:从 "Clapton" 到 "Walter"。宇宙飞船运算符按字典顺序比较字符串,与 Groovy 的自定义对象排序方法无缝集成。

$ groovy SortUsers.groovy
[John Doe - gardener, Roger Roe - driver, Lucia Smith - accountant, 
 Paul Newman - firefighter, Adam Clapton - teacher, Jane Walter - pilot]
[Adam Clapton - teacher, John Doe - gardener, Paul Newman - firefighter, 
 Roger Roe - driver, Lucia Smith - accountant, Jane Walter - pilot]

比较混合类型

宇宙飞船运算符可以优雅地处理混合类型,根据需要转换操作数,这使其对于异构数据比较非常通用。

MixedTypes.groovy
def values = [5, "10", 3.14, "2"]
values.sort { a, b -> a <=> b }
println values

a <=> b 对混合类型(整数、字符串、浮点数)的 values 进行排序。Groovy 在可能的情况下将字符串强制转换为数字,结果为 [3.14, "2", 5, "10"]。数字比较优先,显示了该运算符在处理类型多样性方面的灵活性。

$ groovy MixedTypes.groovy
[3.14, 2, 5, 10]

使用宇宙飞船进行过滤

除了排序,宇宙飞船运算符还可以通过与阈值进行比较来过滤集合,利用其在条件逻辑中的数值输出。

FilterSpaceship.groovy
def numbers = [15, 7, 22, 3, 19, 10]
def threshold = 12
def above = numbers.findAll { it <=> threshold > 0 }
println above

it <=> threshold > 0 查找大于 12 的数字。如果 it <=> threshold 的结果是 1 (it > 12),则该数字被包含在内,结果为 [15, 22, 19]。这直接在过滤器中使用运算符的结果,将其用途从排序扩展到选择任务。

$ groovy FilterSpaceship.groovy
[15, 22, 19]

自定义多属性排序

宇宙飞船运算符可以链接比较来进行多标准排序,在主要标准相同时比较次要属性,从而提供精细的控制。

MultiSort.groovy
class Product {
    String name
    int price

    Product(String name, int price) {
        this.name = name
        this.price = price
    }

    String toString() { "${name} (\$${price})" }
}

def products = [
    new Product("Laptop", 1200),
    new Product("Mouse", 25),
    new Product("Laptop", 800),
    new Product("Keyboard", 50)
]

products.sort { a, b ->
    def nameCmp = a.name <=> b.name
    nameCmp != 0 ? nameCmp : a.price <=> b.price
}
println products

a.name <=> b.name 首先按名称排序。如果名称相等(0),则 a.price <=> b.price 来打破平局。 "Laptop" 按价格 (800, 1200) 排序,然后是 "Keyboard" 和 "Mouse"。这演示了运算符的链接能力在分层排序中的应用。

$ groovy MultiSort.groovy
[Laptop ($800), Laptop ($1200), Keyboard ($50), Mouse ($25)]

宇宙飞船在条件逻辑中的应用

运算符的 -1、0、1 输出可以驱动 if-else 逻辑,提供一种紧凑的方式来对值之间的关系进行分类,而无需进行多次比较。

ConditionalSpaceship.groovy
def x = 7
def y = 10
def result = (x <=> y) switch {
    -1 -> "less than"
    0  -> "equal to"
    1  -> "greater than"
}
println "$x is $result $y"  // Output: 7 is less than 10

x <=> y (7 < 10) 返回 -1,通过 switch 映射为 "小于"。这避免了单独的 <==> 检查,使用运算符的结果简洁地描述了 xy 之间的关系。

来源

Groovy 运算符文档

本教程涵盖了 Groovy 宇宙飞船运算符 <=>,展示了其在排序、过滤和自定义比较中的应用,并附带实际示例。

作者

我叫 Jan Bodnar,我是一名充满激情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教授编程方面拥有超过八年的经验。

列出 所有 Groovy 教程