【问题标题】:Is is reasonable, and is there a benefit to a Scala Symbol class that extends AnyVal?是合理的,扩展 AnyVal 的 Scala Symbol 类是否有好处?
【发布时间】:2013-09-07 14:57:19
【问题描述】:

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 有更深入了解的 cmets 会很有启发性。特别是,上面是否通过引用相等提供了有效的映射?

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

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

【问题讨论】:

  • 关于能够拥有可以扩展的符号类型的有用性的任何答案?作为一个具体的例子,在遗传学中有遗传标记和个体,两者都通过一个简单的字符串名称来识别。同一个标记或个人可能会多次从数据文件中读取,因此符号的经济性是有意义的。但是采用符号的方法或 Map 可能肯定需要 MarkerSymbol 或 IndividualSymbol。 scala.Symbol 很容易修改以允许子分类。我能看到它没有的唯一原因是 'XYZ 糖。

标签: scala


【解决方案1】:

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

参见符号的source code。 Equals 被覆盖并重新定义以使用 eq 方法进行参考比较。

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

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

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

编辑:从不在任何注重性能的程序中使用 string.intern。与微不足道的实习生表相比,string.intern 的性能也很糟糕。看到这个SO question and answer。简单的实习表见上面 Symbol 的源码。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      对于AnyVal,该类实际上是String。神奇地添加的方法和类型安全只是编译器技巧。是String 被到处转移。

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

      【讨论】:

        猜你喜欢
        • 2013-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多