【问题标题】:How does Scala implement the addition operator behind the scenes?Scala 如何在幕后实现加法运算符?
【发布时间】:2016-05-06 14:45:54
【问题描述】:

在 Scala 中,+ 操作符实际上是一个名为 + 的方法,由对象实现。在Int的情况下,来自Int.scala

/** Returns the sum of this value and `x`. */
def +(x: Int): Int

可以使用infix notation 调用没有副作用的 1-arity 方法:

// this
caller method callee
// and this
caller.method(callee)
// are identical, so
1 + 2
// is actually
(1).+(2)

但我在 Int.scala 上找不到该语言实际上是如何在 + 方法中执行整数加法的。

它是怎么做的?

【问题讨论】:

    标签: scala operator-overloading operators


    【解决方案1】:

    编译器魔法。编译器翻译成 JVM 上的内在“iadd”指令。

    class Test {
    
      def first(x: Int, y: Int) = x + y
    
      def second(x: Int, y: Int) = (x).+(y)
    }
    

    在任何一种情况下,这都完全符合您的期望

    $ javap -c Test.class
    Compiled from "Test.scala"
    public class Test {
      public int first(int, int);
        Code:
           0: iload_1
           1: iload_2
           2: iadd
           3: ireturn
    
      public int second(int, int);
        Code:
           0: iload_1
           1: iload_2
           2: iadd
           3: ireturn
    
     public Test();
        Code:
           0: aload_0
           1: invokespecial #20                 // Method java/lang/Object."<init>":()V
           4: return
    }
    

    其他 JVM 原始操作也会发生类似的事情

    如果你在自己的类上实现“+”,它只是被分派到一个普通的方法调用中

    class Test2 {
      def +(t2: Test2) = "whatever"
    
      def test = this + this
    }
    

    变成

    $ javap -c Test2.class
    Compiled from "Test2.scala"
    public class Test2 {
      public java.lang.String $plus(Test2);
        Code:
           0: ldc           #12                 // String whatever
           2: areturn
    
      public java.lang.String test();
        Code:
           0: aload_0
           1: aload_0
           2: invokevirtual #19                 // Method $plus:(LTest2;)Ljava/lang/String;
           5: areturn
    
      public Test2();
        Code:
           0: aload_0
           1: invokespecial #23                 // Method java/lang/Object."<init>":()V
           4: return
    }
    

    请注意,该方法名为“$plus”。这是因为就 JVM 而言,“+”不是有效的方法名称。其他无效 JVM 名称的符号也有类似的翻译。

    在所有这些情况下,scalac 使用静态类型来确定是发出方法调用还是 JVM 原语。

    实际的决定是在https://github.com/scala/scala/blob/2.11.x/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala 中做出的,这个阶段发生在编译器链的很晚阶段。在大多数情况下,之前的所有阶段都将 x + y 视为将是一个方法调用,而不管 x 的类型如何。

    【讨论】:

      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 1970-01-01
      • 2020-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多