1

Scalaの変数に関するスコープとの正確な取引は何ですか?

中かっこを開くと、外側の変数の値にアクセスできます (変数の場合はそれらを変更します)。

scala> var mmm = 4
mmm: Int = 4

scala> {
     | println(mmm)
     | mmm += 2
     | println(mmm)
     | }
4
6

scala> println(mmm)
6

しかし、オデルスキーは 180 ページまたは彼の著書で次のように述べています。

Scala プログラムでは、内部スコープでは外部変数が見えなくなるため、内部変数は同名の外部変数を隠すと言われます。

これはさらに奇妙に思えます:

scala> val a = 4
a: Int = 4

scala> {
     | println(a)
     | }
4

それで、内側のスコープで作成されたコピーを取得しますか?

scala> val a = 4
a: Int = 4

scala> {
     | val a = 8
     | }

不変の場合、なぜもう一度 val と言えるのでしょうか?

scala> val a = 4
a: Int = 4

scala> {
     | println(a)
     | val a = 8
     | println(a)
     | }

しかし、これについてはエラーが発生します:

error: forward reference extends over definition of value a
              println(a)
4

2 に答える 2

5

ブロックに新しいものを作成すると、新しいものは古い (外側の) ものを覆い隠します。そうでない場合は、外側のものを参照します。

ブロック内のどこに新しいブロックが作成されるかは問題ではありません。それがどこかに現れると、外側のものを覆い隠します。

そう、

val a = 5
{ println(a) }  // This is outer a

val a = 5
{ val a = 8; println(a) }  // This is inner a

val a = 5
{ println(a); val a = 8 }  // This is broken
                           // you try to print the inner a
                           // but it doesn't exist yet

編集:最後のものを解凍しましょう

val a = 5
// Okay, I have something called a

{  // Oh, new block beginning!  Maybe there are local variables
  println(a)
  val a = 8    // Yeah, there's one!
               // And it's got the same name as the outer one
               // Oh well, who needs the outer one anyway?
}

// Waitaminute, what was that block supposed to do?
{
  println(a)   // Inner block has an a, so this must be the inner a
  val a = 8    // Which is 8
}

// Hang on, operations happen in order
{
  println(a)   // What inner a?!

// Abort, abort, abort!!!!
于 2012-11-29T17:44:24.247 に答える
1

ブロックは、外部変数自体の可視性を変更しません。Oderskyの引用で説明されているように、内部スコープ内で同じ名前の変数を宣言する場合のみ。

最初の2つの例ではこれを行わないため、外側の変数は内側のスコープ内にはっきりと表示され、Oderskyの引用は適用されません。内側のaスコープのは外側のスコープのと同じでaあり、コピーは必要ありません。

ただし、3番目の例では、2つaのsは2つの独立val変数です。つまり、内側は外側を再定義aせず、Oderskyの引用に従ってシャドウイングするだけです。例:a

val a = 4
println(a)  // prints 4 - outer a
{
  val a = 8;
  println(a)  // prints 8 - inner a
}
println(a)  // prints 4 - outer a in scope again

つまり、内側のブロックを出た後a、元の値の外側がまだそこにあることがわかります。

println(a)ただし、3番目の例で示すコードは、最初のステートメントが参照する変数である言語仕様についての深い知識がないと判断が難しいため、非常にあいまいです。正確なリファレンスは手元にありませんが、このスタイルは本質的にエラーが発生しやすいのにメリットがないため、このようなコードはコンパイラによって許可されていないと思います。

于 2012-11-29T17:44:03.703 に答える