2014-09-21 57 views
3

使用元组分配多个变量并将它们分配到多个语句中有区别吗?元组的多元赋值比多个赋值语句慢吗?

例如,以下代码片段有区别吗?

// multiple assignment using tuples 
val (x, y) = (str.length, str.substring(1, 2)) 

// multiple-statement assignment 
val x = str.length 
val y = str.substring(1, 2) 

回答

3

的差异。使用元组的方法实际上是调用一个提取器(unapply方法),这会在运行时产生成本。第二种方法肯定更快。

要了解差异,请参阅两种方法的反编译,以显示两种方法。你可以清楚地看到第一种方法如何导致更多的操作。

这里需要注意的一点很重要,第一个表达式需要自动装箱到java.lang.Integer(因为Tuple2接受对象),而第二个表达式使用的是没有装箱的值。

public void m1(java.lang.String); 
    Code: 
     0: new   #16     // class scala/Tuple2 
     3: dup   
     4: aload_1  
     5: invokevirtual #22     // Method java/lang/String.length:()I 
     8: invokestatic #28     // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 
     11: aload_1  
     12: iconst_1  
     13: iconst_2  
     14: invokevirtual #32     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     17: invokespecial #35     // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V 
     20: astore_3  
     21: aload_3  
     22: ifnull  75 
     25: aload_3  
     26: invokevirtual #38     // Method scala/Tuple2._1$mcI$sp:()I 
     29: istore  4 
     31: aload_3  
     32: invokevirtual #42     // Method scala/Tuple2._2:()Ljava/lang/Object; 
     35: checkcast  #18     // class java/lang/String 
     38: astore  5 
     40: new   #16     // class scala/Tuple2 
     43: dup   
     44: iload   4 
     46: invokestatic #28     // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 
     49: aload   5 
     51: invokespecial #35     // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V 
     54: astore  6 
     56: aload   6 
     58: astore_2  
     59: aload_2  
     60: invokevirtual #38     // Method scala/Tuple2._1$mcI$sp:()I 
     63: istore  7 
     65: aload_2  
     66: invokevirtual #42     // Method scala/Tuple2._2:()Ljava/lang/Object; 
     69: checkcast  #18     // class java/lang/String 
     72: astore  8 
     74: return   
     75: new   #44     // class scala/MatchError 
     78: dup   
     79: aload_3  
     80: invokespecial #47     // Method scala/MatchError."<init>":(Ljava/lang/Object;)V 
     83: athrow   

    public void m2(java.lang.String); 
    Code: 
     0: aload_1  
     1: invokevirtual #22     // Method java/lang/String.length:()I 
     4: istore_2  
     5: aload_1  
     6: iconst_1  
     7: iconst_2  
     8: invokevirtual #32     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     11: astore_3  
     12: return   
} 
+0

字节代码不能说明整个故事。你必须看看JVM优化器对这件事做了什么。它可能完全可以优化它。这并不难:Scala.js优化器可以做到这一点,所以如果JVM也做到这一点,我不会感到惊讶。 – sjrd 2014-09-22 04:41:01

+0

@sjrd感谢您的留言。 JVM可能可以优化其中的一部分。在该行的10000个调用之后,它应该能够摆脱'throw'指令,也许还有演员阵容。但是,请注意,我没有提到性能存在差异。我不得不衡量它说。我只是指出了理论上的差异,帮助人们更好地理解Scala是如何工作的,揭示了编译器隐藏的东西。 – 2014-09-22 09:20:32

+0

对不起,我说我没有提到性能,但我确实做到了。其实,我不认为JVM可以优化整个表达式。在编译阶段,Scala.js应该能够做到这一点。但是由于Scala编译器没有这样做,我不认为JVM会忽略分配对象和装箱值的指令。请检查我的拳击更新。 – 2014-09-22 09:27:20