學(xué)習(xí)Scala的變量范圍
現(xiàn)在你已經(jīng)看過了Scala的內(nèi)建控制結(jié)構(gòu),我們將在本節(jié)中使用它們來解釋Scala里的范圍是如何起作用的。
51CTO編輯推薦:Scala編程語言專題
Scala程序里的變量定義有一個能夠使用的范圍:scope。范圍設(shè)定的最普通不過的例子就是,大括號通常引入了一個新的范圍,所以任何定義在打括號里的東西在括號之后就脫離了范圍。這條規(guī)則有幾個例外,因為在Scala里有時候你可以用大括號代替小括號。表達(dá)式語法的替代品是這種使用大括號例子的其中之一。作為演示,請看一下代碼7.18里展示的函數(shù):
代碼 7.18 打印乘法表時的變量范圍
- def printMultiTable() {
- var i = 1
- // 這里只有i在范圍內(nèi)
- while (i <= 10) {
- var j = 1
- // 這里i和j在范圍內(nèi)
- while (j <= 10) {
- val prod = (i * j).toString
- // 這里i,j和prod在范圍內(nèi)
- var k = prod.length
- // 這里i,j,prod和k在范圍內(nèi)
- while (k < 4) {
- print(" ")
- k += 1
- }
- print(prod)
- j += 1
- }
- // i和j仍在范圍內(nèi);prod和k脫離范圍
- println()
- i += 1
- }
- // i仍在范圍內(nèi);j,prod和k脫離范圍
- }
printMultiTable函數(shù)打印了乘法表。 函數(shù)的第一個語句引入了變量i并初始化為整數(shù)1。然后你可以在函數(shù)余下的部分里使用名稱i。
printMultiTable接下去的語句是一個while循環(huán):
你可以在這使用i因為它仍在范圍內(nèi)。在while循環(huán)的第一個語句里,你引入了另一個變量,叫做j,并再次初始化為1。因為變量j定義在while循環(huán)的大括號內(nèi),所以只能用在while循環(huán)里。如果你想嘗試在while循環(huán)的大括號之后,在那個說j,prod和k已經(jīng)出了范圍的注釋后面,再用j做點(diǎn)兒什么事,你的程序就編譯不過了。
- while (i <= 10) {
- var j = 1
- ...
- }
本例中定義的所有變量——i,j,prod和k——都是本地變量:local variable。對于它們被定義的函數(shù)來說是“本地”的。每次函數(shù)被調(diào)用的時候,一整套全新的本地變量將被使用。
一旦變量被定義了,你就不可以在同一個范圍內(nèi)定義同樣的名字。比如,下面的腳本不會被編譯通過:
然而,你可以在一個內(nèi)部范圍內(nèi)定義與外部范圍里名稱相同的變量。下列腳本將編譯通過并可以運(yùn)行:
- val a = 1
- val a = 2 // 編譯不過
- println(a)
執(zhí)行時,這個腳本會先打印2,然后打印1,因為定義在內(nèi)部打括號里的a是不同的變量,將僅在大括號內(nèi)部有效。另外,本例中在a的第一個定義之后需要加分號,因為Scala的分號推斷機(jī)制不會在這里加上分號。Scala和Java間要注意的一個不同是,與Scala不同,Java不允許你在內(nèi)部范圍內(nèi)創(chuàng)建與外部范圍變量同名的變量。在Scala程序里,內(nèi)部變量被說成是遮蔽:shadow了同名的外部變量,因為在內(nèi)部范圍內(nèi)外部變量變得不可見了。
- val a = 1;
- {
- val a = 2 // 編譯通過
- println(a)
- }
- println(a)
或許你已經(jīng)注意到了一些在解釋器里看上去像是遮蔽的東西:
解釋器里,你可以對你的核心內(nèi)容重用變量名。撇開別的不說,這樣能允許你當(dāng)發(fā)現(xiàn)你在解釋器里第一次定義變量時犯了錯誤的時候改變主意。你能這么做的理由是因為,在理論上,解釋器在每次你輸入新的語句時都創(chuàng)建了一個新的嵌套范圍。因此,你可以把之前解釋的代碼虛擬化認(rèn)為是:
- scala> val a = 1
- a: Int = 1
- scala> val a = 2
- a: Int = 2
- scala> println(a)
- 2
- val a = 1;
- {
- var a = 2;
- {
- println(a)
- }
- }
這段代碼可以像Scala腳本那樣編譯和執(zhí)行,而且像輸入到解釋器里的代碼那樣,打印輸出2。請記住這樣的代碼對讀者來說是很混亂的,因為在嵌套范圍中變量名稱擁有了新的涵義。通常更好的辦法是選擇一個新的有意義的變量名而不是遮蔽外部變量。
【相關(guān)閱讀】