简体   繁体   English

Scala中模式匹配的速度有多快

[英]How fast is pattern matching in Scala

I'm new to Scala. 我是Scala的新手。 When I am learning it by reading Scala code written by others, one of the most distinguishing feature I find in Scala code that is different from other languages is its pattern matching. 当我通过阅读其他人编写的Scala代码来学习它时,我在Scala代码中发现的与其他语言不同的一个最显着特征是它的模式匹配。

At the same time I feel the convenience and expressiveness it brings, I can't help being curious of the potential performance cost behind it -- generally speaking, how fast is match ? 与此同时,我感受到它带来的便利性和表现力,我不禁对它背后的潜在性能成本感到好奇 - 一般来说, match速度有多快?

Firstly, without "advanced" features such as matching parameters of constructors, match in Scala, IMO, is the counterpart of switch-case in other languages. 首先,如果没有“高级”功能,例如匹配构造函数的参数,Scala中的match ,IMO,是其他语言中switch-case的对应物。 For instance, 例如,

color match {
  0 => println "color is red!"
  1 => println "color is green!"
  2 => println "color is blue!"
}

As a novice, I want to know if the code above is exactly as fast as equivalent code in if-else statement? 作为一个新手,我想知道上面的代码是否和if-else语句中的等效代码一样快?

Secondly, now taking those "advanced" features back, for instance: 其次,现在恢复这些“高级”功能,例如:

expr match {
  Animal(name) => ...
  Animal(name, age) => ...
  Animal(_, _, id) => ...
}

As for the code above or other features of match(list matching, pair matching, etc.), I am curious about how Scala implemented these fancy usage? 至于上面的代码或匹配的其他功能(列表匹配,配对匹配等),我很好奇Scala如何实现这些花哨的用法? And most importantly, how fast can I expect these code to be? 最重要的是,我能期望这些代码有多快? (Say, are they still as fast as the match in the first case? Or maybe slightly slower? Or extremely slow owing to the use of some technology such as reflection?) (比方说,它们仍然和第一种情况下的match一样快吗?或者可能稍微慢一些?或者由于使用某些技术(如反射)而非常慢?)

Thanks in advance! 提前致谢!

First snippet is translated to bytecode's TableSwitch (or LookupSwitch ) and is as fast as Java's switch/case: 第一个代码段被转换为字节码的TableSwitch (或LookupSwitch ),并且与Java的switch / case一样快:

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

Second snipped is translated to bunch of unapply/isInstanceOf/null checks calls, and is (obviously) slower than tableswitch . 第二个剪切被转换为一堆unapply/isInstanceOf/null checks调用,并且(显然)比tableswitch慢。 But it has same (or better, if compiler can optimize something) performance as manual checking via isInstanceOf (no reflection or similar stuff): 但它具有相同(或更好,如果编译器可以优化某些东西)性能作为手动检查通过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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM