我认为我理解Scala 2.10的新“值类”功能,与Haskell的newtype
进行比较:
trait BoundedValue[+This] extends Any { this: This =>
def upperBound: This
def lowerBound: This
}
class Probability @throws(classOf[IllegalArgumentException]) (v: Double) extends AnyVal with BoundedValue[Probability] {
val value: Double = if ((v >= 0.0) && (v <= 1.0)) v else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]")
override val upperBound: Probability = new Probability(0.0)
override val lowerBound: Probability = new Probability(1.0)
// Implement probability arithmetic here;
// will be represented by Double at runtime.
}
我的问题是,对于使用声明它的Scala包的Java代码,值类是如何出现的?值类是从Java端显示为引用类,还是完全擦除(因此它显示为它包装的类型)?换句话说,当Java涉及源级别时,值类是如何类型安全的?
修改
根据SIP-15文档(在Daniel的回答中链接),上面的代码将无法编译,因为不允许值类具有任何初始化逻辑,因为v
必须显式为val或Probability
必须在其伴随对象上使用unbox
方法和相应的box
方法,因为值类必须只有一个字段。正确的代码是:
trait BoundedValue[This <: BoundedValue[This]] extends Any { this: This =>
def upperBound: This
def lowerBound: This
}
class Probability private[Probability] (value: Double) extends AnyVal with BoundedValue[Probability] {
@inline override def upperBound: Probability = new Probability(0.0)
@inline override def lowerBound: Probability = new Probability(1.0)
@inline def unbox: Double = value
// Implement probability arithmetic here;
// will be represented by Double at runtime (mostly).
}
object Probability {
@throws(classOf[IllegalArgumentException])
def box(v: Double): Probability = if ((v >= 0.0) && (v <= 1.0)) new Probability(v) else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]")
}
然而,问题本身仍然有效。
答案 0 :(得分:6)
值类编译为普通类,并且可能显示为引用。
它们的神奇之处在于,当值类没有逃避范围时,它的所有痕迹都会从代码中删除,从而有效地内联所有代码。当然,还要提供额外的安全性。
另见SIP-15,其中解释了机制。