1

scala.Symbol 的一个问题似乎是它有两个对象,Symbol 和它所基于的 String。

为什么不能通过定义 Sym 来消除这个额外的对象:

class Sym private(val name:String) extends AnyVal {
    override def toString = "'" + name
}

object Sym {
    def apply(name:String) = new Sym(name.intern)
}

诚然,对象分配对性能的影响可能很小,但那些对 Scala 有更深入了解的人的评论会很有启发性。特别是,上面是否通过引用相等提供了有效的映射?

上面简单的“Sym”的另一个优点是在一个以地图为中心的应用程序中,其中有很多字符串键,但在字符串命名许多完全不同类型的事物的情况下,可以定义类型安全的 Sym 类,以便地图明确显示程序员、编译器和重构工具真正的关键是什么。

(Symbol 和 Sym 都不能扩展,前者显然是可以选择的,后者是因为它扩展了 AnyVal,但 Sym 很简单,只需用适当的名称进行复制)

4

3 回答 3

4

不能将 Symbol 作为 AnyVal。Symbols 相对于简单字符串的主要好处是保证 Symbols 是被实习的,因此您可以使用简单的引用比较而不是昂贵的字符串比较来测试符号的相等性。

参见 Symbol 的源代码。Equals 被覆盖并重新定义以使用eq方法进行参考比较。

但不幸的是 AnyVal 不允许您重新定义平等。来自用户定义值类的SIP-15 :

C 可能没有定义具体的 equals 或 hashCode 方法。

因此,虽然有一种方法可以在不产生运行时开销的情况下重新定义相等性非常有用,但不幸的是这是不可能的。

编辑:永远不要在性能很重要的任何程序中使用 string.intern。与微不足道的实习生表相比,string.intern 的性能也很糟糕。请参阅此SO 问题和答案。简单的实习表见上面 Symbol 的源代码。

于 2013-09-07T19:58:09.917 回答
0

因为AnyVal类实际上是String. 神奇地添加的方法和类型安全只是编译器技巧。它是String四处转移的。

对于模式匹配(Symbol我想的目的)Scala需要一个对象的类。因此—— Symbol extends AnyRef

于 2013-09-07T19:31:45.120 回答
0

不幸的是,只要将 AnyVal 放入集合中,就会强制为 AnyVal 分配对象,例如您示例中的 Map 。这是因为值类必须转换为集合的类型参数,并且转换为新类型总是强制分配。这几乎消除了将 Sym 声明为值类的任何优势。有关值类,请参阅Scala 文档页面中的分配详细信息。

于 2013-09-07T15:24:26.147 回答