簡體   English   中英

為什么即使左側沒有定義新變量,else if 語句中的短變量聲明也不會編譯失敗?

[英]Why a short variable declaration in an else if statement doesn't fail to compile even though no new variable is being defined on the left side?

以下代碼預計會因編譯錯誤而失敗:

package main

import (
    "fmt"
)

func main() {
    x := 10
    x := x + 1
    fmt.Println(x)
}

編譯錯誤是:

./prog.go:9:4: no new variables on left side of :=

所以我期待這段代碼也會因錯誤而失敗:

package main

import (
    "fmt"
)

func main() {
    if x := 10; x < 10 {
        fmt.Println("if block: x:", x)
    } else if x := x + 1; x < 20 {
        fmt.Println("else if block: x: ", x)
    }
}

這是 output:

else if block: x:  11

為什么即使else if x:= x + 1中的:=運算符沒有定義任何新變量,第二個程序也會成功?

根據 Go 規范,這里是if語句的定義方式:

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ].

后來,在聲明和 Scope部分中說:

在塊中聲明的標識符可以在內部塊中重新聲明。 內部聲明的標識符在 scope 中,表示內部聲明所聲明的實體。

現在, if語句是一個隱式塊

每個“if”、“for”和“switch”語句都被認為在其自己的隱式塊中。

然后從IfStmt定義中可以看出,在關鍵字else之后可能會出現:

  • 一個Block ,即else { /* code */ }
  • IfStmt再次,就像你的情況一樣,即else if /* statement */ { /* code */ } 這意味着IfStmt是遞歸的,它是另一個IfStmt的隱式塊(仍然是隱式塊)。 因此它滿足重新聲明標識符的條件。

還與顯式塊進行比較:

func foo() {
    x := 10
    {
        x := 20
        fmt.Println("Inner x:", x) // 20
    }
    fmt.Println("Outer x:", x) // 10
}

由於您的第二個 x:= 在另一個 scope 中,您正在處理兩個不同的 x 變量。 所以它對你來說看起來像同一個 x,但它不是,即使它基於外部 x 的值,它也不會影響它。 您正在打印的 x 是內部 x。

考慮這個例子

package main

import (
    "fmt"
)

func main() {

    // Define x in the func scope
    x := 10
    // Print out global scope x
    fmt.Printf("x1:%v\n", x)

    // Not allowed (x already defined in this scope)
    //x := x + 1

    // Allowed (different x)
    {
        x := x + 1
        // Print new local scope x (this is a second x)
        fmt.Printf("x2:%v\n", x)

    }

    // Allowed (different x defined)
    if x := x + 1; x > 10 {
        // Print new local scope x (this is a third x)
        fmt.Printf("x3:%v\n", x)
    }

    // Print out global scope x
    fmt.Printf("x1:%v\n", x)
}

在此示例中,您有 3 個 x 變量。 func 級別第一,{} 中的第一個作用域,然后是 if 塊中的另一個(再次獨立)。 所有這三個都是獨立的,並且兩個內部的在定義后(在該范圍內)會影響外部的,因此即使您選擇將 x 2 和 3 設為初始 x 的基礎,它們也不會影響其值。

當您在末尾打印出全局 scope x 時,您可以看到這一點,並且因為 x3 不受 x2 值的影響,所以我們最終在 function 的末尾:

  • x1:10
  • x2: 11
  • x3: 11

在這個例子中,

func main() {
    if x := 10; x < 10 {
        fmt.Println("if block: x:", x)
    } else if x := x + 1; x < 20 {
        fmt.Println("else if block: x: ", x)
    }
}

您在兩個地方定義 x 變量是正確的,因為該變量的 scope 在 if 和 else 下。 像這樣考慮這段代碼

在此處輸入圖像描述

如果你在這里看到我們有兩個街區,街區 1 和街區 2

兩個塊都有自己的 scope,無論您在該塊內部定義什么,外部都無法訪問。

試試這個,你會得到一個錯誤。

func main() {
    if x := 10; x < 10 {
        fmt.Println("if block: x:", x)
    } else if x := x + 1; x < 20 {
        fmt.Println("else if block: x: ", x)
    }
    fmt.Println("What is the value of x: ", x)
}

錯誤:./prog.go:13:45:未定義:x

因為您正試圖在外部訪問該變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM