清单 6. Groovy Person 类
class Person {
private name
def age
def getName() {
name
}
@Override
String toString() {
"${name} is ${age} years old."
}
}
def bob = new Person(name: "Bob", age:42)
println(bob.name)
|
在 清单 6 的 Groovy 代码中,定义一个字段 def 会得到一个存取函数和赋值函数。如果仅喜欢其中一个函数,可自行定义它,就像我对 name 属性所做的那样。尽管该方法名为 getName() ,但我仍然可以通过更直观的 bob.name 语法访问它。 如果希望 Groovy 自动为您生成 equals() 和 hashCode() 方法对,可以向类中添加@EqualsAndHashCode 注释。该注释使用 Groovy 的抽象语法树 (Abstract Syntax Tree, AST) 转换 生成基于您的属性的方法(参阅 参考资料)。在默认情况下,此注释仅考虑属性(而不考虑字段);如果添加了 includeFields=true 修饰符,它也会考虑字段。 Clojure 的映射式记录 可在 Clojure 中像其他语言中一样创建相同 Person 类,但这并不符合语言习惯。传统上,Clojure 等语言依靠映射(名称-值对)数据结构来持有这种类型的信息,并使用了一些处理该结构的函数。尽管仍然可以在映射中建模结构化的数据,但目前更常见的情形是使用记录。记录是 Clojure 对具有属性(常常是嵌套的)的类型名的更加正式的封装,每个实例具有相同的语义含义。(Clojure 中的记录就像类 C 语言中的 struct 。) 例如,请考虑以下人员定义: (def mario {:fname "Mario"
:age "18"})
|
鉴于此结构,可以通过 (get mario :age) 访问 age 。简单的访问是映射上的一个常见操作。借助 Clojure,可以利用使用键充当着映射上的存取函数 的语法糖,以便使用更有效的 (:age mario) 速记法。Clojure 期望对映射进行操作,所以它提供了大量语法糖来简化此操作。 Clojure 还拥有访问嵌套的映射元素的语法糖,如清单 7 所示: 清单 7. Clojure 的速记式访问
(def hal {:fname "hal"
:age "17"
:address {:street "Enfield Tennis Academy"
:city "Boston"
:state "MA"}})
(println (:fname hal))
(println (:city (:address hal)))
(println (-> hal :address :city))
|
在 清单 7 中,我定义了一个名为 hal 的嵌套数据结构。对外部元素的访问按预期进行 ((:fname hal) )。如 清单 7 中倒数第二行所示,Lisp 语法执行 “内外” 评估。首先,必须从 hal 获取address 记录,然后访问 city 字段。因为 “内外” 评估是一种常见用法,所以 Clojure 提供了一个特殊运算符(-> thread 运算符)来反转表达式,使它们更加自然、更具可读性:(-> hal :address :city) 。 可使用记录创建等效的结构,如清单 8 所示: 清单 8. 使用记录创建结构
(defrecord Person [fname lname address])
(defrecord Address [street city state])
(def don (Person. "Don" "Gately"
(Address. "Ennet House" "Boston", "MA")))
(println (:fname don))
(println (-> don :address :city))
|
在 清单 8 中,我使用 defrecord 创建了相同的结构,得到了一种更加传统的类结构。借助 Clojure,可以通过熟悉的映射操作和方言在记录结构中实现同样便捷的访问。 Clojure 1.2 围绕常见操作的记录定义通过两个工厂函数添加了语法糖: - ->类型名称, 接收字段的位置参数
- ->映射->类型名称, 字段值的关键字映射
使用符合语言习惯的函数,代码由 清单 8 转换成版本 清单 9. 清单 9. Clojure 的漂亮的语法糖
(def don (->Person "Don" "Gately"
(->Address "Ennet House" "Boston", "MA")))
|
在许多情况下,记录比映射和扁平结构更受欢迎。首先,defrecord 创建了一个 Java 类,使它更容易在多方法定义中使用。然后,defrecord 指定更多任务,在您定义记录时启用字段验证和其他细微处理。第三,记录速度快得多,尤其在您拥有一组固定的已知键的时候。 Clojure 结合使用记录和协议来构造代码。未来的一期文章将介绍它们的关系。
结束语 与 Java 语言相比,所有 3 种 Java 下一代语言都提供了更便捷的语法。Groovy 和 Scala 使构建类和常见情形更加轻松,而 Clojure 使映射、记录和类能够无缝地互操作。所有 Java 下一代语言的一个共同主旨是消除不必要的样板代码。在下一期文章中,我将继续探讨这个主题并讨论一些异常。 |