3

考虑以下非常简单的代码:

class A(val a: String, val b: Int)
object Test {
  implicit class wrap(obj: A) {
    def fn = obj.a + obj.b
  }

  def main(args: Array[String]) =
    println(new A("Hello", 1).fn)
}

反汇编代码产生:

public void main(java.lang.String[]);
  Code:
   0:   getstatic   #29; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   3:   aload_0
   4:   new #31; //class A
   7:   dup
   8:   ldc #33; //String Hello
   10:  iconst_1
   11:  invokespecial   #36; //Method A."<init>":(Ljava/lang/String;I)V
   14:  invokevirtual   #38; //Method wrap:(LA;)LTest$wrap;
   17:  invokevirtual   #42; //Method Test$wrap.fn:()Ljava/lang/String;
   20:  invokevirtual   #46; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   23:  return

fn编译器在隐式使用时有效地创建了包装对象。

虽然我很清楚 JIT 编译可以消除这一点,但过早的优化是不好的,而且我不太可能在我的大多数代码中遇到任何性能问题,但在后台创建静态函数似乎并不就像编译器的大量工作一样,并且会消除这一点。

所以,你去吧,我只是好奇:Scala 团队决定不包括这个优化有什么特别的原因吗?

4

1 回答 1

10

在这种情况下,无法判断您是要将 A 用作普通类还是打算将其用作隐式包装器。对于简单地包装类型的类,您可以利用值类,这些值类应该去糖化为您想要的行为(也就是没有包装类),只需使用第一个参数作为包装值的方法调用。不幸的是,它们只适用于具有一元构造函数的类。

 object Test {
   implicit class A(val a: String) extends AnyVal {
     def foo: String = a 
   }

   def main(args: Array[String]) {
     "Hello World!".foo
   }
 }

这具有像这样的代码通常编译成模块加载的副作用,然后是invokevirtual。这可以进行优化,米格尔·加西亚(Miguel Garcia)正在努力使这种情况成为“真正的静态”

于 2013-04-29T19:17:38.210 回答