Java中的用户定义值类是怎样的?

8

我认为我能通过与Haskell的newtype进行比较来理解Scala 2.10中新的“value class”功能:

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]")

}

这个问题本身仍然有效,不过需要注意的是。

1
在你的测试程序中,你能否从Java推出包装后的值到有效范围之外? - David Harkness
@DavidHarkness,我现在没有可以使用2.10.0-M4的机器,所以我不知道。我会在有机会时进行检查。 - Ptharien's Flame
1个回答

6

值类编译成普通类,并且可能出现为引用。

它们的神奇之处在于,当值类不逃离作用域时,所有与其相关的代码都被擦除,有效地内联所有代码。当然,这也提供了额外的类型安全性。

另请参见 SIP-15,其中解释了其机制。


谢谢!我以为我已经读过SIP了,但实际上我还没有。 - Ptharien's Flame
2
一个同样有趣的问题是,“在没有值类型本身的平台上(例如JVM),Scala值类型如何编码?”另一个问题是,“在具有值类型本身的平台上(例如CLI),Scala值类型如何编码?”例如,Scala值类型是否可以编译为CLI上的结构体?它们是否保证始终被编译为结构体? - Jörg W Mittag
1
你的问题非常有趣,但我意识到不仅CLI结构体不受支持(上次我读SIP时没有提到它们),而且它们可能也没什么用。值类只能有一个字段,就像Haskell的newtypes一样,因此我认为使用结构体而不是基元类型并不能帮助解决问题。 结构体在内存使用方面有很多优势,但要使用它们,应该提供一个单独的机制,即请求此行为的注释,可以忽略它。语义问题是,结构体应该只在CLI上从AnyVal继承,而不是在JVM上。 - Blaisorblade
2
据我所知,如果一个值类型超出了其作用域,它会被包装(我的意思是,该值将被包装在对象中,而不是内联)。实际上,该值“几乎总是”内联的 :-) 请参见我的问题的答案在这些情况下,Scala值类将被“包装”,对吗? - KajMagnus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接