2011-09-07 43 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之外的变量,请首先声明它们以使它们在要使用的范围内可访问。