Go编译错误:未定义变量。

7

我是一个新手程序员,对Go语言更是不熟悉。我写了一个小的Go程序,但是在编译时出现了未定义变量的错误。

以下是我的代码:

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

然而,这些变量直到代码运行时才会被定义。此外,“lookup”函数尚未编写,它只返回传递给它的内容。我知道lookup和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

p.s. 我已经阅读了 http://tip.goneat.org/doc/go_faq.html#unused_variables_and_imports ,我同意如果这只是语法问题,我仍然想要修复它,只是我不知道该怎么做!

2个回答

5

Go中了解声明和作用域

在switch或select语句中,每个子句都充当一个隐式块。

块嵌套并影响作用域。

声明标识符的作用域是指标识符表示指定的常量、类型、变量、函数或包的源文本范围。

在函数内部声明的常量或变量标识符的作用域从ConstSpec或VarSpec(对于短变量声明的ShortVarDecl)的结尾开始,并在最内层包含块的结尾结束。

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

短变量声明的作用域仅限于switch语句中每个casedefault子句所包含的块(最内层的包含块)。artistalbumyear变量在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"))

与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初在同一块中以相同的类型声明,并且至少有一个非空变量是新的。因此,重新声明只能出现在多变量短声明中。
因此,在switch case子句中不再使用短变量声明来声明(和分配)artistalbumyear变量,因为这会隐藏外部块中的变量声明,它们只被赋值。

这个完美地运行了,谢谢。同时,感谢您详尽的解释和对文档的引用! - rick

3

当您需要有条件地分配变量时,必须在条件之前进行声明。因此,请不要这样写:

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)
}

即使您设置了默认值,编译器也不喜欢它们没有被先声明。或者可能是因为它不喜欢它们在每个条件中都声明了两次,我不确定。

现在,我们首先声明变量,然后在switch条件中设置它们的值。一般规则是:如果您打算在if/switch/for之外使用变量,请先声明它们以使其在将要使用的范围内可访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接