Scala如何在幕后实现加法运算符?

时间:2016-01-29 00:28:17

标签: scala operator-overloading operators

在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 语言如何在 + 方法中实际执行整数加法。

怎么做?

1 个答案:

答案 0 :(得分:11)

编译器魔术。编译器转换为内在的" iadd"关于JVM的说明。

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原语操作也会发生类似的事情

如果你实施&#34; +&#34;在你自己的课上,它只是被分派到正常的方法调用

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
}

请注意,该方法的名称为&#34; $ plus。&#34;那是因为&#34; +&#34;就JVM而言,它不是一个有效的方法名称。其他符号不是有效的JVM名称具有相似的翻译。

在所有这些情况下,scalac使用静态类型来确定是否发出方法调用或JVM原语。<​​/ p>

实际的确定是在https://github.com/scala/scala/blob/2.11.x/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala中进行的,这个阶段在编译器链中发生得很晚。在大多数情况下,所有之前的阶段都会将x + y看作是一个方法调用,无论x的类型如何。