为什么``对象'里面的`val`不能自动最终?

0__*_*0__ 33 scala final field

vals(?)在单例对象中自动最终的原因是什么?例如

object NonFinal {
   val a = 0
   val b = 1

   def test(i: Int) = (i: @annotation.switch) match {
      case `a` => true
      case `b` => false
   }
}
Run Code Online (Sandbox Code Playgroud)

结果是:

<console>:12: error: could not emit switch for @switch annotated match
          def test(i: Int) = (i: @annotation.switch) match {
                                                     ^
Run Code Online (Sandbox Code Playgroud)

object Final {
   final val a = 0
   final val b = 1

   def test(i: Int) = (i: @annotation.switch) match {
      case `a` => true
      case `b` => false
   }
}
Run Code Online (Sandbox Code Playgroud)

编译时没有警告,因此可能会生成更快的模式匹配表.

必须添加final似乎纯粹恼人的噪音给我.这不是object最终本身,因此也是其成员?

Tra*_*own 25

这在规范中明确说明,它们是自动最终的:

最终类或对象的成员也是最终的,因此final修饰符通常也是多余的.但请注意,常量值定义(第4.1节)确实需要显式final修饰符,即使它们是在最终类或对象中定义的.

你的final例子用2.10-M7编译时没有错误(或警告),所以我假设@switch早期版本的检查有问题,而且成员实际上是最终的.


更新:实际上这比我预期的更好奇 - 如果我们使用2.9.2或2.10-M7编译以下内容:

object NonFinal {
  val a = 0
}

object Final {
  final val a = 0
}
Run Code Online (Sandbox Code Playgroud)

javap 确实有所不同:

public final class NonFinal$ implements scala.ScalaObject {
  public static final NonFinal$ MODULE$;
  public static {};
  public int a();
}

public final class Final$ implements scala.ScalaObject {
  public static final Final$ MODULE$;
  public static {};
  public final int a();
}
Run Code Online (Sandbox Code Playgroud)

即使值定义的右侧不是常量表达式,您也会看到同样的事情.

所以我会留下我的答案,但这并不是决定性的.

  • 我以为你只能打开常数值,在这种情况下,2.10-M7已经删除了你所引用的`final`的要求.没有? (2认同)

psp*_*psp 21

你不是在问"他们为什么不是最终的",而是在问"他们为什么不进行内联".只是碰巧最后是你如何提示你希望它们内联的编译器.

它们未自动内联的原因是单独编译.

object A { final val x = 55 }
object B { def f = A.x }
Run Code Online (Sandbox Code Playgroud)

当你编译它时,Bf返回55,字面意思是:

public int f();
  0: bipush        55
  2: ireturn       
Run Code Online (Sandbox Code Playgroud)

这意味着如果你重新编译A,B将无视这一变化.如果x在A中没有标记为final,则Bf看起来像这样:

  0: getstatic     #19                 // Field A$.MODULE$:LA$;
  3: invokevirtual #22                 // Method A$.x:()I
  6: ireturn       
Run Code Online (Sandbox Code Playgroud)

另外,为了纠正其中一个答案,final并不意味着scala中的不可变.

  • 最终并不意味着不变.尝试"final var x = 1; x = 2". (3认同)