group of people sitting on floor

Apache Groovy 中的变量:强大、简洁且易于使用

Apache Groovy 变量可以通过显式指定数据类型或使用 def… 来定义
首页 » 博客 » Apache Groovy 中的变量:强大、简洁且易于使用

Groovy 是一种强大、简洁且易于学习的语言; 自 2008 年以来我就爱上了它。我通过这个 系列 旨在展示它能为您做些什么。(如果您尚未安装 Groovy,请 阅读介绍。)

为什么现在在第六篇文章中讨论变量? 我保证接下来会有有趣的内容。

首先编写一个非常简单的脚本,声明一个整数,设置其值,打印出来并打印出其类

1 int s
2 s = 42
3 println s
4 println s.getClass()

现在运行脚本

$ groovy Groovy05a.groovy
42
class java.lang.Integer
$

请注意,尽管将变量 s 声明为 int 类型,但它似乎实际上是 java.lang.Integer 类的一个实例。 实际上就是这种情况——Groovy 中看起来像是原始类型的东西(intfloatdoubleboolean)根本不是原始类型。 它们是类,就像 StringDate 一样。

您也知道您不需要指定变量 s 的类型。 您可以使用 def 关键字来声明它,如下面的脚本所示

1 def s
2 s = 42
3 println s
4 println s.getClass()

运行此脚本并查看会发生什么

$ groovy Groovy05b.groovy
42
class java.lang.Integer
$

因此,似乎将 42 分配给上面的 s 会以某种方式使 s 成为 java.lang.Integer 的实例。 但那是对的吗? 尝试另一个实验

1 def s
2 s = 42
3 println s
4 println s.getClass()
5 s = “The meaning of everything”
6 println s
7 println s.getClass()

等等,您真的认为这会奏效吗? 好吧,试试看

$ groovy Groovy05c.groovy
42
class java.lang.Integer
The meaning of everything
class java.lang.String
$

好的,所以似乎您可以自由使用 s 来保存任何类的实例。 但是,如果您回到显式键入 s 会发生什么?

1 int s
2 s = 42
3 println s
4 println s.getClass()
5 s = "The meaning of everything"
6 println s
7 println s.getClass()

运行它

$ groovy Groovy05d.groovy
42
class java.lang.Integer
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘The meaning of everything’ with class ‘java.lang.String’ to class ‘int’
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object ‘The meaning of everything’ with class ‘java.lang.String’ to class ‘int’
at Groovy05d.run(Groovy05d.groovy:5)
$

因此,在其声明中显式键入变量或仅使用 def 之间存在很大差异。 很高兴知道这一点。 想象一下,如果您声明一个变量,您打算保存年份值,后来您(或其他人)感到困惑并尝试将日期分配给该变量。 您可以放心地知道,只要您将变量声明为 int,就不能将 Date 值分配给它。

唯一的陷阱——总会有一个——是将某物声明为 String,然后稍后为其分配 int 值。 不起作用,对吧? 好吧,它有点起作用——大多数 Groovy 类都有一个 toString() 方法,可以自动“转换”为 String 值。

例如

1 String s
2 s = 42
3 println s
4 println s.getClass()
5 s = “The meaning of everything”
6 println s
7 println s.getClass()

它在运行时产生这个

$ groovy Groovy05e.groovy
42
class java.lang.String
The meaning of everything
class java.lang.String
$

在这里,您可以看到整数值 42 已转换为字符串。 这可能会产生一些奇怪的错误,例如

1 String s
2 s = 42
3 println s
4 println s.getClass()
5 s *= 2
6 println s
7 println s.getClass()

看看第五行,您“忘记” s 是一个字符串,并尝试将其乘以 2? 运行这个

$ groovy Groovy05f.groovy
42
class java.lang.String
4242
class java.lang.String
$

果然,42 * 2 = 4242。

这是一个很酷的想法:如果您根本不声明 s 会怎么样? 让我们试试看

1 s = 42
2 println s
3 println s.getClass()
4 s *= 2
5 println s
6 println s.getClass()

Groovy 应该会抱怨,对吧? 运行这个

$ groovy Groovy05g.groovy
42
class java.lang.Integer
84
class java.lang.Integer
$

第一行中的 s 来自哪里? 事实证明,Groovy 脚本有这个叫做“绑定”的东西——具体来说,总是有一个 groovy.lang.Binding 的实例,称为 binding,它在任何 Groovy 脚本中都被隐式声明和可用。 任何未声明的变量都会出现在绑定中。 这个脚本演示了它

1 s = 42
2 println s
3 println s.getClass()
4 println binding.getVariables()

运行它

$ groovy Groovy05h.groovy
42
class java.lang.Integer
[args:[], s:42]
$

请注意其中的变量 s 及其值 42。 您还应该注意到变量 args ——这是命令行上的参数来自 Groovy 脚本内部的位置。 最后,请注意 getVariables() 方法返回变量及其值的映射。

最后,我赞赏 Groovy 为使用 Binding 实例提供的一些不错的语法支持

1 s = 42
2 println s
3 println “binding.getVariable(‘s’) ${binding.getVariable(‘s’)}”
4 println “binding.getProperty(‘s’) ${binding.getProperty(‘s’)}”
5 println “binding.s ${binding.s}”
6 println “binding[‘s’] ${binding[‘s’]}”

运行它

$ groovy Groovy05i.groovy
42
binding.getVariable(‘s’) 42
binding.getProperty(‘s’) 42
binding.s 42
binding[‘s’] 42
$

看到所有这些访问“变量” s 的不同方式的等价性了吗?

绑定是 Groovy 提供的一种很酷的机制,允许从外部将有用的东西注入到脚本中。 当在 Groovy 中制作特定领域语言时,它尤其有用。

结论

事实证明,在 Groovy 脚本中声明变量——甚至更重要的是,不声明变量——是一个具有一定深度的主题。 以我的经验来看,对于任何我希望长期维护的代码,最好声明变量的类型,而不是使用 def 关键字。 另外,请注意声明为 String 的变量。 最后,我敦促您深入研究绑定,因为它们是使 Groovy 变得 groovy 的原因之一!

照片由 Alina Grubnyak 拍摄于 Unsplash

作者

留下评论

发表评论

如果您喜欢这篇文章,您可能也喜欢这些