8

我知道value class在编译时在 scala 中内联操作。

也许像这样

case class A(i: Int) extends AnyVal {
   def +(that: A) = A(this.i + that.i)
} 
A(1) + A(2) // After compile it equals to 1 + 2 

但这对我来说似乎没什么大不了的。

它可能会提高性能,但是,

呼叫this.i + that.i似乎并不比i + i

为什么我们需要value classscala 和任何用例???

4

3 回答 3

12

为什么要将单个值包装到附加类中?

一个重要的用例是类型安全。假设您具有可以乘以货币的功能,如下所示:

def multiply(factor: Int, amount: Int): Int = ???

这样做的问题是很容易混淆这两个参数,从而错误地调用函数。使用值类,您可以创建一个Money类型并重新编写函数,如下所示:

case class Money(amount: Int) extends AnyVal
def multiply(factor: Int, amount: Money): Money = ???

现在使用您的特殊Money类型,如果您尝试以错误的顺序传递参数,编译器会告诉您。

如果它不是一个值类,人们可能会说在某些情况下增加的类型安全不值得性能损失。但是,对于值类,您没有运行时开销(尽管有限制:http: //docs.scala-lang.org/overviews/core/value-classes.html)。

实现相同目标的替代方法是 scalaz 中的未装箱(无运行时开销)标记类型:http: //eed3si9n.com/learning-scalaz/Tagged+type.html

请注意,例如 haskellnewtype用于相同的想法:https ://wiki.haskell.org/Newtype

于 2016-11-20T14:25:42.950 回答
10

让我们看看 Scala 如何处理值类(-print选项)。

case class A(i: Int) extends AnyVal {
   def +(that: A) = A(this.i + that.i)
} 
A(1) + A(2)

被翻译成:

final def +$extension($this: Int, that: Int): Int = $this.+(that)
...
A.+$extension(1, 2)

如您所见,Scala 避免使用 classA并简单地添加IntInt返回Int. 同时:

case class A(i: Int) {
   def +(that: A) = A(this.i + that.i)
} 
A(1) + A(2)

被翻译成:

def +(that: A): A = new A(this.i().+(that.i()))
...
new A(1).+(new A(2))

所以要计算1 + 2你需要实例化类A三次。

于 2016-11-20T14:22:19.760 回答
1

值类是 Scala 中避免分配运行时对象的一种机制。这是通过定义新的 AnyVal 子类来实现的。

更多关于价值类的信息在这里价值类

于 2016-11-20T13:46:07.237 回答