为什么值类仅限于AnyVal?

时间:2012-12-08 18:49:24

标签: scala haskell wrapper primitive-types newtype

据我所知,Scala中的值类只是将基本类型(如IntBoolean)包装到另一种类型而不引入额外的内存使用。所以它们基本上被用作普通类的轻量级替代品。

这让我想起了Haskell的newtype符号,它也用于将现有类型换成新的类型,从而为一些数据引入了一个新的接口而不消耗额外的空间(看两种语言的相似性,例如限制为HaskellScala中包含一个字段的“构造函数”。

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

或者Scala中是否还有一种方法可以为Scala.AnyRef类型定义这样的包装器?

2 个答案:

答案 0 :(得分:12)

他们不仅限于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)

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

答案 1 :(得分:2)

推理记录为Scala Improvement Process (SIP)-15。正如阿列克谢·罗曼诺夫在评论中指出的那样,我的想法是使用现有关键字来寻找一个表达式,以便编译器确定这种情况。

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

  1. 编译器需要遍历每个类的整个约束列表。并且因为值类的状态是隐式的,所以稍后可以通过向类添加成员来打破二进制兼容性
  2. 编译器添加了更多约束,例如值类变为final禁止继承。因此,您必须将这些约束添加到任何想要以这种方式内联的类中,然后您只能获得额外的冗长。
  3. 人们可以想到其他假设的结构,例如: val class Meter(underlying: Double) { ... },但extends AnyVal IMO的优势在于不需要语法扩展。所有原始类型都在扩展AnyVal,因此有一个很好的类比(没有引用,没有继承,有效表示等)。