2012-11-29 172 views
1

關於Scala變量的範圍的確切處理是什麼?變量的嵌套/內部範圍

當我打開大括號我仍然可以訪問外瓦爾的價值(如果瓦爾對其進行修改):

scala> var mmm = 4 
mmm: Int = 4 

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

scala> println(mmm) 
6 

但他的書Odersky的說,180頁或

In a Scala program, an inner variable is said to shadow a like-named outer variable, because the outer variable becomes invisible in the inner scope.

這似乎更加古怪:

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) 

回答

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!!!! 
+0

IM仍然困惑,我只是不能讓我的頭一輪的(我猜它是我的錯):現在 我知道外殼是不同的 - 但我可以理解它是如何工作的,比如說: martin @ mintbox〜$'a = 5 martin @ mintbox〜$(echo $ a; a = 8; echo $ a)馬丁@ mintbox〜$回聲$一個 5' 那裏我可以看到創建了一個範圍(用var和子shell的副本可以在不影響外部的VAL - 但可以在內部副本 但如何你解釋我的第一個例子,內部增量改變外部值? – mbrambley

+0

用Q編輯過 – mbrambley

+0

@mbrambley - 內部增量是外部值的增量。你不會因爲你打開一些大括號而丟掉所有的變量。這就像在這方面進行子類化:孩子仍然可以訪問父項中的所有內容,但可以添加自己的內容(或替換父項內容)。這不是_actually_子類化,但也許這會幫助你看到發生了什麼。 –

1

塊不改變外部變量本身的知名度。只有在內部範圍內聲明具有相同名稱的變量時才如Odersky報價解釋。

您的前兩個示例不會這樣做,因此外部變量在內部範圍內顯而易見,並且Odersky的引用不適用。內部範圍中的a與外部範圍中的a相同,不涉及複製。

然而,在第三示例中,兩個a s爲兩個獨立val變量,即內a重新定義a,只是陰影它作爲每Odersky的的報價,例如:

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 

Ie在退出內部塊之後,您會看到具有其原始值的外部a仍然存在。

但是,您在第三個示例中顯示的代碼非常含糊,因爲如果沒有深入的語言規範知識,您的第一個println(a)語句引用哪個變量就很難決定。我手邊沒有確切的參考文獻,但我相信編譯器不允許這樣的代碼,因爲這種風格本身不容易出錯,但這種風格沒有任何好處。