近日在知乎闲逛时,和某位抱怨《Rust 编程之道》的答主起了争执:她认为此书将 Trait 翻译成“特型”是极糟糕的译法,足以媲美遗臭万年的鲁棒性(Robust),而笔者对此有不同意见。今天借这个话题谈谈笔者的一些思考,希望能起到抛砖引玉的效果。
笔者没读过《Rust 编程之道》,因此本文不涉及对此书的评价。
翻译问题
为什么“鲁棒性”会招致如此多的反对?概因 Robust 本可信达雅地翻译成“稳健性”,译者却偏偏选择了令人费解的“鲁棒性”,平白增加了理解门槛。default 翻译成“缺省”也是同样的问题。相较之下,Trait 的翻译要有争议的多:
首先,Trait 应不应该翻译?这个问题见仁见智。对于评论留言等场合,直接使用英文也无伤大雅;但对于教科书和文章,使用中文更显正式。考虑到 Trait 是一个常用的专有术语,有一个合适的中文表述是非常重要的。
其次,Trait 应该如何翻译?Trait 一词的原意是特质、特性和特征,中文社区似乎倾向于译为“特征”。问题是特征的语感不好,“高阶特征约束”读起来就不怎么顺口。如果一定要从中选一个译名,我推荐学习 Scala 官方文档,将 Trait 译为“特质”。
虽然术语 Trait 来自 Scala,但 Rust 的 Trait 更接近 Haskell 的 Typeclass:如果说 type/class 是对 value/object 的抽象,那么 trait(typeclass)/interface 就是对 type/class 的抽象。类型可以视为一组值的集合,特型则可以视为一组类型的集合。所以 trait 可以用来约束泛型,而类型可以用来约束变量(和函数参数)。具体来说,Rust :
左边是泛型名,右边是它的特型;:
左边是变量名,右边是它的类型。
泛型参数对应的其实是变量或形参,变量 v
是调用时具体值的标识符,泛型 T
是为给调用时确定的具体类型起了一个标识符。例如,调用泛型函数时可以通过 Turbofish 语法指明泛型参数 T
的具体“值”:
|
|
foo::<usize>(128)
调用把 usize
传给泛型参数 T
,把 128
传给值参数 x
。这在类型为一等公民的 Zig 中更明显:
|
|
“特型”指一组具有指定特点的类型,“特型”可以理解为“更高维”的类型,注意笔者不是在说 HKT。这样翻译有利于初学者在类型、泛型和 Trait 之间建立联系,还便于理解 Trait Object,因为特型对象就是把特型当成类型用,直接用特型约束变量(对象),这和 Go 的 Interface 类似。
组合优于继承
C++、Java 的继承,实际上是类(Class)或类型(Type)的继承:子类继承了父类的数据和方法。Rust 倾向于另一种抽象方式:不同的特型,为每种类型实现它们