作用域敘述了變數及function的可見性和生存週期,可以簡單來說,我在意的是code的哪些部分可以訪問特定的變數,所以我們會去學習這個語言的區域作用域,全域作用域,go有個很經典的問題
package main
import (
"fmt"
)
func main() {
if a := 1; false {
} else if b := 2; false {
} else if c := 3; false {
} else {
fmt.Println(a, b, c)
}
}
以上答案會是什麼
我們先不解答然後,先往下認識
代碼塊是由一對大括號 {} 包裹起來的一系列語句。在 Go 中,代碼塊用於定義一系列語句的邏輯邊界
宇宙塊(Universe Block):
make
, new
, cap
, 和 len
這些關鍵字是 Go 語言的內建函數,它們在任何地方都可以訪問。它們是在宇宙作用域(或稱宇宙塊)中定義的。包作用域(Package Block):
文件作用域(File Block):
import
語句導入其他包時,那個包的名稱的作用域僅限於該文件。其他文件,即使它們是同一個包的,也不能直接使用那個導入的包名稱,除非它們也導入了相同的包。區域/局部作用域:
func exampleFunction() {
x := 10 // x的作用域從這裡開始
if x > 5 {
y := 5 // y的作用域只在這個if語句的大括號內
fmt.Println(y) // 這裡可以訪問y
}
// fmt.Println(y) // 這裡會報錯,因為y在這裡是不可見的
fmt.Println(x) // 這裡可以訪問x
} // x和y的作用域在這裡結束
在 Go 語言中,if 語句(以及其他控制結構,如 for 和 switch)都在隱式的代碼塊中,這意味著你可以在 if 語句中有其自己的變數聲明和作用域
if a:= 1; a > 1 {
...
}
根據上述的隱式的代碼塊原則,我們可以把這段程式碼等價於
{ // 隱式block開始
a := 1
if a > 1 { // 顯式block開始
} // 顯式block結束
} // 隱式block結束
這也可以說明為什麼 a在外面聲明但可以在if裡面使用
if a := 1; a > 1 {
...
} else {
...
}
上面等價於
{ // 隱式block開始
a := 1
if a > 1 { // 顯式block開始
...
} else { // 另一個顯式block開始
...
} // 顯式blocks結束
} // 隱式block結束
上面的a, 可以在其後面的else語句中使用。因為整個if-else結構都在一個隱式的外部代碼塊中,所以在這個隱式代碼塊中聲明的變數在整個if-else結構中都是可見的
if a := 1; a > 1 {
...
} else if b := 2; b > 2 {
...
} else {
...
}
上面等價於
{ // 外部隱式block開始
a := 1
if a > 1 { // 第一個顯式block開始
...
} else { // 第二個隱式block開始,為了包含 else if 和可能的後續 else
b := 2
if b > 2 { // 第二個顯式block開始
...
} else { // 第三個顯式block開始
...
} // 第三個顯式block結束
} // 第二個隱式block結束
} // 外部隱式block結束
如果你在第一個 if 的條件中聲明了一個變數,那麼你可以在 else if 或 else 部分中訪問它。同樣,如果你在 else if 的條件部分中聲明了一個變數,那麼你可以在其後面的 else 部分中訪問它
依照這個規則你應該就有辦法推出第一題的答案了吧
for a, b := 1, 10 ; a < b ; a++ {
...
}
上面的code可以轉為
{
a, b := 1
for ; a< b; a++ {
...
}
}
當你做了以上的轉換,你就可以很清楚的知道你定義的這些變數可以在哪裡使用,哪裡可見,希望對你有幫助