9

我想将 scala 的值类应用于我的一个项目,因为它们使我能够在没有大量开销的情况下丰富某些原始类型(我希望如此)并保持类型安全。

object Position {

  implicit class Pos( val i: Int ) extends AnyVal with Ordered[Pos] {

    def +( p: Pos ): Pos = i + p.i

    def -( p: Pos ): Pos = if ( i - p.i < 0 ) 0 else i - p.i

    def compare( p: Pos ): Int = i - p.i

  }
}

我的问题:每当我使用对象时,继承是否会Ordered强制分配Pos对象(从而引入巨大的开销)?如果是这样:有没有办法绕过这个?

4

1 回答 1

6

每次Pos都将被视为一个Ordered[Pos],分配将会发生。在某些情况下必须进行分配,请参阅http://docs.scala-lang.org/overviews/core/value-classes.html#when_allocation_is_necessary

所以当做像调用这样简单的事情时<,你会得到分配:

val x = Pos( 1 )
val y = Pos( 2 )
x < y // x & y promoted to an actual instance (allocation)

相关规则为(引自上述文章):

每当值类被视为另一种类型(包括通用特征)时,必须实例化实际值类的实例,并且: 此规则的另一个实例是当值类用作类型参数时。

反汇编上面的代码片段证实了这一点:

 0: aload_0
 1: iconst_1
 2: invokevirtual #21                 // Method Pos:(I)I
 5: istore_1
 6: aload_0
 7: iconst_2
 8: invokevirtual #21                 // Method Pos:(I)I
11: istore_2
12: new           #23                 // class test/Position$Pos
15: dup
16: iload_1
17: invokespecial #26                 // Method test/Position$Pos."<init>":(I)V
20: new           #23                 // class test/Position$Pos
23: dup
24: iload_2
25: invokespecial #26                 // Method test/Position$Pos."<init>":(I)V
28: invokeinterface #32,  2           // InterfaceMethod scala/math/Ordered.$less:(Ljava/lang/Object;)Z

可以看出,我们确实有两个类的“新”操作码实例Position$Pos

更新:为了避免在这样的简单情况下分配,您可以手动覆盖每个方法(即使它们只转发到原始实现):

override def <  (that: Pos): Boolean = super.<(that)
override def >  (that: Pos): Boolean = super.>(that)
override def <= (that: Pos): Boolean = super.<=(that)
override def >= (that: Pos): Boolean = super.>=(that)

x < y通过示例进行时,这将删除分配。但是,这仍然存在Pos被视为 an的情况Ordered[Pos](如传递给采用 aOrdered[Pos]或 anOrdered[T]且 T 为类型参数的方法时)。在这种特殊情况下,您仍然会获得分配,并且没有办法解决。

于 2013-05-14T13:28:41.333 回答