scala中的代码块导入内部代价高昂

时间:2016-11-10 11:08:52

标签: performance scala

有时使用import语句来访问对象的多个元素会更方便,更清晰。

例如,代码

x.y.z.a = 1
x.y.z.b = 2
x.y.z.c = 3

可以写成

{
    import x.y.z._

    a = 1
    b = 2
    c = 3
}

显然,当名字更长时,它会更有用。

是否所有工作都是在编译时完成的,还是以某种方式在运行时执行import语句?使用这种风格是否有任何成本,效率或其他方面的成本?

2 个答案:

答案 0 :(得分:5)

您可以使用javap查看自己。从这样的事情开始:

package x.y {
  object z {
    var a = "abc"
    var b = "def"
    var c = "ghi"
  }
}

object Test {
  def withImport: Unit = {
    import x.y.z._

    a = "zyx"
    b = "wvu"
    c = "rst"
  }

  def withoutImport: Unit = {
    x.y.z.a = "zyx"
    x.y.z.b = "wvu"
    x.y.z.c = "rst"
  }
}

使用scalac Test.scala然后javap -c Test\$

进行编译
  public void withImport();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
         3: ldc           #20                 // String zyx
         5: invokevirtual #24                 // Method x/y/z$.a_$eq:(Ljava/lang/String;)V
         8: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
        11: ldc           #26                 // String wvu
        13: invokevirtual #29                 // Method x/y/z$.b_$eq:(Ljava/lang/String;)V
        16: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
        19: ldc           #31                 // String rst
        21: invokevirtual #34                 // Method x/y/z$.c_$eq:(Ljava/lang/String;)V
        24: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      25     0  this   LTest$;
      LineNumberTable:
        line 13: 0
        line 14: 8
        line 15: 16

  public void withoutImport();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
         3: ldc           #20                 // String zyx
         5: invokevirtual #24                 // Method x/y/z$.a_$eq:(Ljava/lang/String;)V
         8: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
        11: ldc           #26                 // String wvu
        13: invokevirtual #29                 // Method x/y/z$.b_$eq:(Ljava/lang/String;)V
        16: getstatic     #18                 // Field x/y/z$.MODULE$:Lx/y/z$;
        19: ldc           #31                 // String rst
        21: invokevirtual #34                 // Method x/y/z$.c_$eq:(Ljava/lang/String;)V
        24: return
        ...

完全相同的字节码。

答案 1 :(得分:4)

是的,所有名称和含义都在编译时解决,import不会影响其他任何内容。

当然,执行的内容仍然是

x.y.z.a = 1
x.y.z.b = 2
x.y.z.c = 3

因此您将获取x.y.z 3次(在此示例中)。如果z

package x.y
object z { ... }

这又是名称解析;但如果你有类似的东西

object x {
  val y = ... // some type which has val z
}

每次调用2次方法调用并将z置于局部变量中会表现得更好(但如果此代码运行得足够频繁,JIT可能会对此进行优化)。