打开字符串

fre*_*low 14 java string scala hashcode switch-statement

我很想知道Java和Scala如何在字符串上实现切换:

class Java
{
    public static int java(String s)
    {
        switch (s)
        {
        case "foo": return 1;
        case "bar": return 2;
        case "baz": return 3;
        default: return 42;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
object Scala {
  def scala(s: String): Int = {
    s match {
      case "foo" => 1
      case "bar" => 2
      case "baz" => 3
      case _ => 42
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

看起来Java会切换哈希码,然后进行单个字符串比较:

 0: aload_0       
 1: dup           
 2: astore_1      
 3: invokevirtual #16    // Method java/lang/String.hashCode:()I
 6: lookupswitch  { // 3
           97299: 40
           97307: 52
          101574: 64
         default: 82
    }
40: aload_1       
41: ldc           #22    // String bar
43: invokevirtual #24    // Method java/lang/String.equals:(Ljava/lang/Object;)Z
46: ifne          78
49: goto          82
52: aload_1       
53: ldc           #28    // String baz
55: invokevirtual #24    // Method java/lang/String.equals:(Ljava/lang/Object;)Z
58: ifne          80
61: goto          82
64: aload_1       
65: ldc           #30    // String foo
67: invokevirtual #24    // Method java/lang/String.equals:(Ljava/lang/Object;)Z
70: ifne          76
73: goto          82
76: iconst_1      
77: ireturn       
78: iconst_2      
79: ireturn       
80: iconst_3      
81: ireturn       
82: bipush        42
84: ireturn       
Run Code Online (Sandbox Code Playgroud)

相比之下,Scala似乎与所有案例进行比较:

 0: aload_1       
 1: astore_2      
 2: ldc           #16    // String foo
 4: aload_2       
 5: invokevirtual #20    // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
 8: ifeq          16
11: iconst_1      
12: istore_3      
13: goto          47
16: ldc           #22    // String bar
18: aload_2       
19: invokevirtual #20    // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
22: ifeq          30
25: iconst_2      
26: istore_3      
27: goto          47
30: ldc           #24    // String baz
32: aload_2       
33: invokevirtual #20    // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
36: ifeq          44
39: iconst_3      
40: istore_3      
41: goto          47
44: bipush        42
46: istore_3      
47: iload_3       
48: ireturn       
Run Code Online (Sandbox Code Playgroud)

是否有可能说服Scala使用哈希码技巧?我宁愿选择O(1)解决方案来解决O(n)问题.在我的真实代码中,我需要与33个可能的关键字进行比较.

Die*_*lla 5

肯定看来这个案例是Scala编译器缺乏优化.当然,该match构造比Java中的switch/case强大得多(并且非常强大),并且优化它要困难得多,但它可以检测这些特殊情况,其中将应用简单的哈希比较.

此外,我不认为这个案例会在惯用的Scala中多次出现,因为除了具有不同的值之外,你总是与具有某种意义的案例类相匹配.