似乎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类,以便映射将最终向程序员,编译器和重构工具展示了密钥的真正含义。
(符号和Sym都不能被扩展,前者显然可以选择,后者因为它扩展了AnyVal,但是Sym很容易只能用适当的名称复制)
答案 0 :(得分:4)
无法将Symbol作为AnyVal。与简单字符串相比,符号的主要优点是可以保证符号被禁用,因此您可以使用简单的引用比较而不是昂贵的字符串比较来测试符号的相等性。
请参阅Symbol的source code。重写了Equals并重新定义以使用 eq 方法进行参考比较。
但不幸的是,AnyVal不允许你重新定义平等。来自SIP-15的用户定义值类:
C可能没有定义具体的equals或hashCode方法。
因此,虽然在不产生运行时开销的情况下重新定义相等性的方法非常有用,但遗憾的是不可能。
编辑:从不在性能很重要的任何程序中使用string.intern。与甚至是一个微不足道的实习生表相比,string.intern的表现太可怕了。见SO question and answer。有关简单的实习表,请参阅上面符号的源代码。
答案 1 :(得分:0)
不幸的是,只要将AnyVal放入集合中,就会强制对象分配,例如示例中的Map。这是因为必须将值类强制转换为集合的类型参数,并且强制转换为新类型总是强制分配。这消除了将Sym声明为值类的几乎任何优点。有关值类,请参阅Scala文档页面中的Allocation Details。
答案 2 :(得分:0)
对于AnyVal
,该类实际上是String
。神奇添加的方法和类型安全只是编译器技巧。这是String
四处转移。
对于模式匹配(Symbol
的目的,我认为)Scala需要一个对象的类。因此 - Symbol extends AnyRef
。