per*_*i4n 9 performance scala implicit value-class
我想将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
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题:每当我使用它们时,继承Ordered强制Pos对象的分配(从而引入很大的开销)吗?如果是这样的话:有没有办法绕过这个?
每次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)
Run Code Online (Sandbox Code Playgroud)
相关规则(引自上文):
每当将值类视为另一种类型(包括通用特征)时,必须实例化实际值类的实例,并且:此规则的另一个实例是将值类用作类型参数时.
反汇编上面的代码片段证实了这一点:
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
Run Code Online (Sandbox Code Playgroud)
可以看出,我们确实有两个类的"新"操作码实例 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)
Run Code Online (Sandbox Code Playgroud)
这将x < y通过示例执行时删除分配.然而,这仍然留下了Pos被视为一种情况的情况Ordered[Pos](如果传递给采用Ordered[Pos]或作为Ordered[T]类型参数的方法).在这种特殊情况下,您仍然可以获得分配,而且无法解决这个问题.