2011-09-07 791 views
3

編程新手/甚至更新。在小程序中遇到問題 - 不會編譯未定義的變量錯誤。驗證碼:go編譯錯誤:undefined變量

package main 

import (
    "fmt" 
    "io" 
    "os" 
) 

const file = "readfile.txt" 
var s string 

func lookup(string) (string, string, string) { 
    artist := s 
    album := s 
    year := s 

    return artist, album, year 
} 

func enterdisk() (string, string, string) { 
    var artist string 
    var album string 
    var year string 

    println("enter artist:") 
    fmt.Scanf("%s", &artist) 

    println("enter album:") 
    fmt.Scanf("%s", &album) 

    println("enter year:") 
    fmt.Scanf("%s", &year) 

    return artist, album, year 
} 

func main() { 

    println("enter UPC or [manual] to enter information manually:") 
    fmt.Scanf("%s", &s) 

    s := s 
    switch s { 
     case "manual\n": artist, album, year := enterdisk() 
     default: artist, album, year := lookup(s) 
    } 

    f,_ := os.OpenFile(file, os.O_APPEND|os.O_RDWR, 0666) 
    io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n")) 

    f.Close() 
    println("wrote data to file") 
} 

和錯誤:

catalog.go:49: undefined: artist 
catalog.go:49: undefined: album 
catalog.go:49: undefined: year 

然而,這些變量將不會被直到代碼運行定義。此外,「查找」函數尚未寫入,它只是返回它傳遞的內容。我知道查找和Enterdisk函數可以自己工作,但我正在嘗試測試switch語句。

我曾嘗試宣告主變量,但我得到這個錯誤:

catalog.go:49: artist declared and not used 
catalog.go:49: album declared and not used 
catalog.go:49: year declared and not used 

附:我讀http://tip.goneat.org/doc/go_faq.html#unused_variables_and_imports,我同意,如果這只是語義,我仍然想解決它。我只是不知道如何!

回答

4

閱讀關於blocksdeclarations and scopeGo

Each clause in a switch or select statement acts as an implicit block.

Blocks nest and influence scoping.

The scope of a declared identifier is the extent of source text in which the identifier denotes the specified constant, type, variable, function, or package.

The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.

switch s { 
    case "manual\n": artist, album, year := enterdisk() 
    default: artist, album, year := lookup(s) 
} 
. . . 
io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n")) 

artistalbum,和year變量的short variable declarationsswitchcasedefault情況下條款的範圍開始,並且每個子句(含最內塊)內結束。 artist,albumyear變量不再存在並且對WriteString()語句不可見。

相反,寫:

var artist, album, year string 
switch s { 
case "manual\n": 
    artist, album, year = enterdisk() 
default: 
    artist, album, year = lookup(s) 
} 
. . . 
io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n")) 

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared in the same block with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration.

因此,artistalbum,和year變量使用short variable declarations開關殼體子句內部,因爲這會隱藏變量聲明不再聲明(和分配)在外部塊中,它們僅被分配。

+0

這工作完美,謝謝。此外,感謝您對文檔的全面解釋和參考! – rick

2

當您有條件地分配變量時,您必須在條件之前聲明它們。因此,而不是:

switch s { 
    case "manual\n": artist, album, year := enterdisk() 
    default: artist, album, year := lookup(s) 
} 

...試試這個:

var artist, album, year string 

switch s { 
    case "manual\n": artist, album, year = enterdisk() 
    default: artist, album, year = lookup(s) 
} 

(即使您已設置了默認,編譯器不喜歡,他們不首先聲明或許沒有關係。不喜歡他們被宣佈兩次,在每種情況下,我不確定)

您會看到,現在我們首先聲明變量,並在開關條件中設置它們的值。一般規則是:如果要使用if/switch/for之外的變量,請首先聲明它們以使它們在要使用的範圍內可訪問。