
使用 Apache Groovy 的展开运算符优化您的代码
通过展开运算符,增强您对 Groovy 集合的理解。本指南深入探讨如何使用它来组织、组合和更改列表和映射,最终提高代码的可读性和有效性。
我们已经介绍了 Closure
如何方便地操作列表或映射元素,并特别仔细地研究了排序。现在我们将看看展开运算符,它提供了一种不同的方式来对列表或映射的元素应用转换。(如果您尚未安装 Groovy,请阅读本系列的介绍 系列。)
Groovy 有两个相关的运算符,它们提供了一种简洁的方式来对 Collection 的所有成员执行操作——展开点运算符——以及将集合的成员“解集合”为单个元素——展开运算符。让我们看看如何使用它们使我们的 Groovy 代码更紧凑、更具表现力、更易读和更易于维护。
首先,展开运算符有助于合并列表和映射。
考虑一下这个
1 def l = [1, 5, 6, 7]
2 def s = [2, 3, 4]
3 l[2] = s
4 println "l $l"
5 l = [1, 5, 6, 7]
6 l = [*l.take(1), *s, *l.takeRight(l.size() - 1)]
7 println "l $l"
第一行定义了列表 l
,其第一个和第二个元素值之间存在明显的间隔。
第二行定义了子列表 s
,它可以放入 l
中的间隙。
第三行使用 List
接口的 putAt()
方法将子列表 s
插入到列表 l
中——行 l[2] = s
等效于 l.putAt(2, s)
。
第四行打印结果。
第五行将 l
重置为其原始值。
第六行使用 take()
方法获取 l
的第一个元素的子列表,并使用 takeRight()
方法获取 l
的剩余元素的子列表。通过在第 6 行的每个子列表前放置 *
或展开运算符,我们将它们“解列表”为它们的元素。
第七行打印结果。
让我们看看它是什么样子的
$ groovy Groovy17a.groovy
l [1, 5, [2, 3, 4], 7]
l [1, 2, 3, 4, 5, 6, 7]
$
请注意,第一次尝试使列表 l
中嵌入了子列表 s
,而第二次尝试给了我们一个新的扁平列表。
我们可以对第一种情况下的 l
应用 flatten()
方法,以将子列表元素提升到列表中。
我们可以对映射执行与列表相同的过程,只需进行一个小的语法更改——*
运算符与冒号一起使用——如果 sm
是子映射,则 *:sm
将 sm
的成员提取到映射中。
*.
运算符是将方法应用于列表或映射的每个元素的一种方式。这是一个例子
1 def l = [1, 2, 3, 4, 5]
2 println "l $l"
3 println "l*.plus(2) ${l*.plus(2)}"
4 println "l*.multiply(2) ${l*.multiply(2)}"
5 println "l*.power(2) ${l*.power(2)}"
第一行定义了我们的测试列表,其中包含整数 1 到 5。
第二行打印列表。
第三行打印一个新列表,其元素均比 l
的原始元素大 2。
第四行打印一个新列表,其元素均是 l
的原始元素的两倍。
第五行打印一个新列表,其元素均是 l
的原始元素的平方。
运行它
$ groovy Groovy17b.groovy
l [1, 2, 3, 4, 5]
l*.plus(2) [3, 4, 5, 6, 7]
l*.multiply(2) [2, 4, 6, 8, 10]
l*.power(2) [1, 4, 9, 16, 25]
$
您可以使用 List
的 collect()
方法产生相同的结果
l*.plus(2)
这产生的结果与
l.collect { e -> e + 2 }
这种等效性表明,我们可以通过键从类实例列表或映射值中挖掘出字段值
1 def l = [
2 [temp: 96.3, gender: 'male', pulse: 70],
3 [temp: 96.7, gender: 'male', pulse: 71],
4 [temp: 96.9, gender: 'male', pulse: 74],
5 [temp: 97.0, gender: 'male', pulse: 80],
6 [temp: 97.1, gender: 'male', pulse: 73],
7 [temp: 97.1, gender: 'male', pulse: 75],
8 [temp: 97.1, gender: 'male', pulse: 82],
9 [temp: 97.2, gender: 'male', pulse: 64],
10 [temp: 97.3, gender: 'male', pulse: 69],
11 [temp: 99.0, gender: 'female', pulse: 81],
12 [temp: 99.1, gender: 'female', pulse: 80],
13 [temp: 99.1, gender: 'female', pulse: 74],
14 [temp: 99.2, gender: 'female', pulse: 77],
15 [temp: 99.2, gender: 'female', pulse: 66],
16 [temp: 99.3, gender: 'female', pulse: 68],
17 [temp: 99.4, gender: 'female', pulse: 77],
18 [temp: 99.9, gender: 'female', pulse: 79],
19 [temp: 100.0, gender: 'female', pulse: 78],
20 [temp: 100.8, gender: 'female', pulse: 77]]
21 println "l*.temp ${l*.temp}"
运行它
$ groovy Groovy17c.groovy
l*.temp [96.3, 96.7, 96.9, 97.0, 97.1, 97.1, 97.1, 97.2, 97.3, 99.0, 99.1, 99.1, 99.2, 99.2, 99.3, 99.4, 99.9, 100.0, 100.8]
$
结论
展开运算符 *
是一种将集合的元素提取到周围集合中的方法。展开点运算符 *.
是一种将方法应用于集合的每个元素,或从类实例列表或映射中提取特定字段或键值对的方法。
这两种操作都可以使用 Groovy 中的其他工具实现,但是采用展开运算符,特别是展开点运算符提供的“将列表视为整体”或“将映射视为整体”的观点可能是一件好事。
呼叫所有 LISP 爱好者:对于展开运算符和展开点运算符,是否有任何我可能忽略的隐藏的亮点或独特的用例?
留下评论