web-dev-qa-db-ja.com

「private val」と「private final val」が異なるのはなぜですか?

Scala参照)のセクション4.1を見るまで、private valprivate final valは同じだと思っていました。

定数値の定義は次の形式です

final val x = e

ここで、eは定数式です(§6.24)。最終修飾子が存在する必要があり、型注釈は指定できません。定数値xへの参照自体は定数式として扱われます。生成されたコードでは、定義の右側に置き換えられますe。

そして、私はテストを書きました:

class PrivateVal {
  private val privateVal = 0
  def testPrivateVal = privateVal
  private final val privateFinalVal = 1
  def testPrivateFinalVal = privateFinalVal
}

javap -c出力:

Compiled from "PrivateVal.scala"
public class PrivateVal {
  public int testPrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #19                 // Method privateVal:()I
       4: ireturn       

  public int testPrivateFinalVal();
    Code:
       0: iconst_1      
       1: ireturn       

  public PrivateVal();
    Code:
       0: aload_0       
       1: invokespecial #24                 // Method Java/lang/Object."<init>":()V
       4: aload_0       
       5: iconst_0      
       6: putfield      #14                 // Field privateVal:I
       9: return
}

バイトコードはScala Referenceが言ったように:private valprivate final valではありません。

scalacが単にprivate valprivate final valとして扱わないのはなぜですか?根本的な理由はありますか?

96
Yang Bo

そのため、これは単なる推測に過ぎませんが、Javaでの厄介な問題でした。右側にリテラルを持つ最終静的変数は、定数としてバイトコードにインライン化されます。ただし、「定数」が変更されると、定義のバイナリ互換性が壊れます。値を変更する必要がある可能性のある最終的な静的変数を定義する場合、Javaプログラマーは、メソッドまたはコンストラクターで値を初期化する。

ScalaのvalはすでにJavaの意味で最終的です。Scalaの設計者は、「定数値をインライン化する許可"。だからScalaプログラマーは、ハックに頼らずにこの動作を完全に制御できます。インライン定数、変更すべきではないが高速な値が必要な場合、" final val "を記述します。彼らは、バイナリの互換性を損なうことなく、単に「val」という値を変更できる柔軟性を求めています。

80
Steve Waldman

ここでの混乱は、不変性とfinalのセマンティクスを混同することから生じると思います。 valsは子クラスでオーバーライドできます。したがって、明示的にマークされていない限り、finalとして扱うことはできません。

@Brian REPLは、行レベルでクラススコープを提供します。参照:

scala> $iw.getClass.getPackage
res0: Package = package $line3

scala> private val x = 5
<console>:5: error: value x cannot be accessed in object $iw
  lazy val $result = `x`

scala> private val x = 5; println(x);
5
8
Connor Doyle