我是Scala的新手。当我通过阅读其他人编写的Scala代码来学习它时,我在Scala代码中发现的与其他语言不同的一个最显着特征是它的模式匹配。
与此同时,我感受到它带来的方便性和表现力,我不能对它背后潜在的性能成本感到好奇 - 一般来说,match
的速度有多快?
首先,没有"高级"在Scala,IMO中,构造函数的匹配参数match
等功能在其他语言中与switch-case
相对应。例如,
color match {
0 => println "color is red!"
1 => println "color is green!"
2 => println "color is blue!"
}
作为一个新手,我想知道上面的代码是否和if-else
语句中的等效代码一样快?
其次,现在采取那些"高级"功能返回,例如:
expr match {
Animal(name) => ...
Animal(name, age) => ...
Animal(_, _, id) => ...
}
至于上面的代码或匹配的其他功能(列表匹配,配对匹配等),我很好奇Scala如何实现这些奇特的用法?最重要的是,我能期望这些代码有多快? (比方说,它们是否仍然和第一种情况下的match
一样快?或者可能稍慢?或者由于使用某些技术(如反射)而非常慢?)
提前致谢!
答案 0 :(得分:8)
第一个代码段被转换为字节码的TableSwitch
(或LookupSwitch
),并且与Java的开关/案例一样快:
scala> def foo(i: Int) = i match {
| case 1 => 2
| case 2 => 10
| case 3 => 42
| case _ => 777
| }
foo: (i: Int)Int
scala> :javap -c foo
Compiled from "<console>"
public class {
public static final MODULE$;
public static {};
Code:
0: new #2 // class
3: invokespecial #12 // Method "<init>":()V
6: return
public int foo(int);
Code:
0: iload_1
1: istore_2
2: iload_2
3: tableswitch { // 1 to 3
1: 44
2: 39
3: 34
default: 28
}
28: sipush 777
31: goto 45
34: bipush 42
36: goto 45
39: bipush 10
41: goto 45
44: iconst_2
45: ireturn
public ();
Code:
0: aload_0
1: invokespecial #18 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #20 // Field MODULE$:L;
8: return
第二个剪辑被转换为一堆unapply/isInstanceOf/null checks
个调用,并且(明显)慢于tableswitch
。但它具有相同(或更好,如果编译器可以优化某些东西)性能作为手动检查通过isInstanceOf
(没有反射或类似的东西):
scala> case class Foo(s: String, i: Int)
defined class Foo
scala> def bar(foo: Foo) = foo match {
| case Foo("test", _) => 1
| case Foo(_, 42) => 2
| case _ => 3
| }
bar: (foo: Foo)Int
scala> :javap -c bar
Compiled from "<console>"
public class {
public static final MODULE$;
public static {};
Code:
0: new #2 // class
3: invokespecial #12 // Method "<init>":()V
6: return
public int bar(Foo);
Code:
0: aload_1
1: astore_2
2: aload_2
3: ifnull 26
6: aload_2
7: invokevirtual #20 // Method Foo.s:()Ljava/lang/String;
10: astore_3
11: ldc #22 // String test
13: aload_3
14: invokevirtual #26 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
17: ifeq 26
20: iconst_1
21: istore 4
23: goto 52
26: aload_2
27: ifnull 49
30: aload_2
31: invokevirtual #30 // Method Foo.i:()I
34: istore 5
36: bipush 42
38: iload 5
40: if_icmpne 49
43: iconst_2
44: istore 4
46: goto 52
49: iconst_3
50: istore 4
52: iload 4
54: ireturn
public ();
Code:
0: aload_0
1: invokespecial #34 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #36 // Field MODULE$:L;
8: return
}