【问题标题】:Why are value classes restricted to AnyVal?为什么值类仅限于 AnyVal?
【发布时间】:2012-11-26 16:06:03
【问题描述】:

据我了解,Scala 中的值类只是将 IntBoolean 等原始类型包装成另一种类型,而不会引入额外的内存使用。所以它们基本上被用作普通类的轻量级替代品。

这让我想起了 Haskell 的 newtype 表示法,它也用于将现有类型包装在新类型中,从而在不占用额外空间的情况下为某些数据引入新接口(要查看两种语言的相似性,请考虑例如限制一个“构造函数”,在 HaskellScala 中都有一个字段。

我想知道为什么引入由编译器内联的新类型的概念没有推广到 Haskell 为任何类型提供零开销类型包装器的方法。为什么 Scala 的人在这里坚持使用原始类型(又名 AnyVal)?

或者 Scala 中是否已经有一种方法可以为 Scala.AnyRef 类型定义此类包装器?

【问题讨论】:

  • extends AnyVal 仅用于表示值类,以免引入新的关键字/语法,也不会破坏现有工具。

标签: scala haskell wrapper primitive-types newtype


【解决方案1】:

他们不限于AnyVal

implicit class RichOptionPair[A,B](val o: Option[(A,B)]) extends AnyVal {
  def ofold[C](f: (A,B) => C) = o map { case (a,b) => f(a,b) }
}

scala> Some("fish",5).ofold(_ * _)
res0: Option[String] = Some(fishfishfishfishfish)

值类有各种限制,使它们像轻量级包装器一样,但只能包装原语不是其中之一。

【讨论】:

    【解决方案2】:

    推理记录为Scala Improvement Process (SIP)-15。正如 Alexey Romanov 在他的评论中指出的那样,这个想法是使用现有的关键字来寻找一个表达式,以允许编译器确定这种情况。

    为了让编译器执行内联,需要应用几个约束,例如包装类是“短暂的”(没有字段或对象成员、构造函数主体等)。您关于自动生成内联类的建议至少有两个问题:

    1. 编译器需要检查每个类的整个约束列表。而且由于作为值类的状态是隐式的,它可能会在稍后通过向类添加成员来翻转,从而破坏二进制兼容性
    2. 编译器添加了更多约束,例如值类变为final 禁止继承。因此,您必须将这些约束添加到任何想要以这种方式内联的类,然后您只会获得额外的冗长。

    人们可以想到其他假设结构,例如val class Meter(underlying: Double) { ... },但 extends AnyVal IMO 的优点是不需要语法扩展。此外,所有原始类型都在扩展AnyVal,因此有一个很好的类比(无引用、无继承、有效表示等)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-11
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多