短变量声明和“变量已声明但未使用”错误

我偶然发现了一个奇怪的问题,下面的代码无法编译:


func main() {

    var val reflect.Value

    var tm time.Time


    if tm, err := time.Parse(time.RFC3339, "2018-09-11T17:50:54.247Z"); err != nil {

        panic(err)

    }

    val = reflect.ValueOf(tm)


    fmt.Println(val, tm, reflect.TypeOf(tm))

}

出现错误(代码是 linter 推荐的代码):


$ go run main.go

# command-line-arguments

./main.go:13:5: tm declared and not used

注意tm变量确实被使用了。


但是,如果我添加一个 else 块 - 一切都按预期编译:


func main() {

    var val reflect.Value

    var tm time.Time


    if tm, err := time.Parse(time.RFC3339, "2018-09-11T17:50:54.247Z"); err != nil {

        panic(err)

    } else {

        val = reflect.ValueOf(tm)

    }


    fmt.Println(val, tm, reflect.TypeOf(tm))

}

这看起来像是编译器中的错误或者可能是已知问题?任何想法?(我正在使用 go 1.11)


编辑:到目前为止所有的回应者。根据:https: //golang.org/ref/spec#Short_variable_declarations


与常规变量声明不同,短变量声明可以重新声明变量,前提是它们最初是在同一块(如果块是函数体,则为参数列表)中较早声明的,具有相同的类型,并且至少有一个非空变量是新的。因此,重新声明只能出现在多变量简短声明中。重新声明不会引入新变量;它只是为原始值分配了一个新值。


慕哥6287543
浏览 100回答 2
2回答

杨魅力

这部分:if tm, err := time.Parse(...)创建一个仅在语句内具有范围的新变量- 它不是您声明为的变量。tmifvar tm time.Time此新变量未在 中使用if,因此会出现错误。请注意,您也没有tm分配外部级别,因此fmt.Println将打印零时间,而不是 time.Parse 返回的时间。要解决此问题:声明err并更改if为:var err errorif tm, err = time.Parse(...)注意这是 GO 中的一个微妙的事情,也是一个相当常见的错误来源。该:=语句实际上可以与已经声明的变量和一个或多个新变量的混合使用 - 如果已经声明的变量在相同的词法范围内。然后,只有新的由自动声明:=,其余的只是分配(与=)。但是,如果您在新范围内使用:=,则所有变量都在该范围内声明,并屏蔽任何具有相同名称的外部范围变量(例如在 ;if注意条件if不在大括号内,但仍被视为如果它在块内; GO 中的{code}the 和其他复合语句也会发生同样的情况)。for

温温酱

您的if语句声明了一个新变量tm,该变量仅存在于if块的范围内并且确实从未使用过:if tm, err := time.Parse(time.RFC3339, "2018-09-11T17:50:54.247Z"); err != nil {     panic(err) }在 Go 中,:=声明一个新变量并对其进行初始化。你的意思可能是:func main() {    var val reflect.Value    var tm time.Time    var err error    // Note the change to normal assignment here instead of :=    if tm, err = time.Parse(time.RFC3339, "2018-09-11T17:50:54.247Z"); err != nil {        panic(err)    }    val = reflect.ValueOf(tm)    fmt.Println(val, tm, reflect.TypeOf(tm))}shortcut运算符在Go Tour of Go:=中进行了演示,并在Go spec中进行了解释,后者包括:它是带有初始化表达式但没有类型的常规变量声明的简写:"var" IdentifierList = ExpressionList .Go 规范中也解释了作用域。
打开App,查看更多内容
随时随地看视频慕课网APP