简体   繁体   English

Scala如何处理方法返回类型中的Any to AnyVal协方差?

[英]How does Scala handle Any to AnyVal covariance in method return types?

An example is worth a thousand words: 一个例子值一千个单词:

class A { def foo: Any = new Object }

class B extends A {
  override def foo: AnyVal = 42
}

In Java, the signature @Override public int foo() wouldn't even be allowed, and the overridden method foo in B could only return the wrapper integer type ( @Override java.lang.Integer foo() ). 在Java中,甚至不允许使用签名@Override public int foo() ,并且B的重写方法foo只能返回包装整数类型( @Override java.lang.Integer foo() )。

Is Scala able to avoid the boxing/unboxing of AnyVal values in the overridden def foo: AnyVal method above? Scala是否能够避免对上面覆盖的def foo: AnyValAnyVal值进行装箱/拆箱def foo: AnyVal方法?

No, it does not. 不,不是的。 Scala has to adhere to emitting the correct bytecode: Scala必须坚持发出正确的字节码:

λ scalac -Xprint:jvm Bar.scala
[[syntax trees at end of                       jvm]] // Bar.scala
package yuval.tests {
  class A extends Object {
    def foo(): Object = new Object();
    def <init>(): yuval.tests.A = {
      A.super.<init>();
      ()
    }
  };
  class B extends yuval.tests.A {
    override def foo(): Object = scala.Int.box(42);
    def <init>(): yuval.tests.B = {
      B.super.<init>();
      ()
    }
  }
}

You can see that although AnyVal was permitted in Scala, the actual method signature for the emitted foo is Object and not AnyVal , and Int is boxed. 您可以看到,尽管AnyVal中允许使用AnyVal ,但是所发出的foo的实际方法签名是Object而不是AnyVal ,并且将Int装箱了。

Yuval's answer can be generalized: erasure of AnyVal is Object (you can see this eg by entering classOf[AnyVal] in the REPL), so whenever you have AnyVal in Scala, you can expect Object in bytecode. Yuval的回答可以概括为:擦除AnyValObject (例如,您可以通过在REPL中输入classOf[AnyVal]来看到此信息),因此,每当在Scala中具有AnyVal时,都可以期望Object用字节码表示。

Eg if you change A to 例如,如果您将A更改为

class A { def foo: AnyVal = 0 }

it's still Object . 它仍然是Object

Maybe there is some situation in which using AnyVal itself will avoid boxing, but I would be surprised. 也许在某些情况下使用AnyVal本身会避免装箱,但我会感到惊讶。 It was created pretty much for compiler's convenience, and picked up another use ( value classes ) later, but it's rarely useful in user code (except for defining value classes). 它的创建几乎是为了给编译器提供方便,后来又有另一种用途( 值类 ),但是在用户代码中很少有用(除了定义值类)。

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

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