2012-12-08 30 views
3

据我明白Scala中值类只是有包裹原始类型像IntBoolean成另一种类型,而不会引入额外的内存使用情况。所以它们基本上被用作普通类的轻量级替代品。为什么值类限制为AnyVal?

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

我想知道的是,为什么引入由编译器内联的新类型的概念并没有被推广到Haskell的任何类型的零开销类型包装的方法。为什么斯卡拉人坚持原始类型(又名AnyVal)?

还是有已​​经在斯卡拉的方式也定义了这种包装的Scala.AnyRef类型?

+0

'扩展AnyVal'只是用来指示值类,以便不引入新的关键字/语法和不会破坏现有的工具。 –

回答

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) 

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

2

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

为了使编译器执行的内联,若干约束适用,如包装类是“短暂的”(无场或对象成员,构造体等)。您自动生成内联类的建议至少有两个问题:

  1. 编译器需要遍历每个类的约束的整个列表。并且由于作为值类的状态是隐含的,所以它可以通过在稍后时间向该类添加成员来翻转,从而打破二进制兼容性。编译器添加了更多约束,例如,值类成为禁止继承的final。所以你必须将这些约束添加到任何想要以这种方式可以被嵌入的类中,然后你只能获得更多的冗长。

有人可能会认为其他假设的结构,例如val class Meter(underlying: Double) { ... },但extends AnyVal IMO的优点是不需要语法扩展。所有原始类型都在扩展AnyVal,所以有一个很好的比喻(没有参考,没有继承,有效的表示等)

相关问题