网络异常,图片无法展示
|
变量隐藏在 Go 中可能会令人困惑,让我们尝试弄清楚。
package main import ( "fmt" "io/ioutil" "log" ) func main() { f, err := ioutil.TempFile("", "") if err != nil { log.Fatal(err) } defer f.Close() if _, err := f.Write([]byte("Hello World\n")); err != nil { log.Fatal(err) } else { fmt.Println("All success") } }
请注意,我们首先从 TempFile
函数创建了两个变量:f
和 err
。然后我们调用 Write
丢弃写入的字节数。我们让函数在 if
语句中调用它。让我们编译,它工作正常。
$ go run main.go All success
现在,与 if
之外的 Write
调用相同的代码:
package main import ( "fmt" "io/ioutil" "log" ) func main() { f, err := ioutil.TempFile("", "") if err != nil { log.Fatal(err) } defer f.Close() // if _, err := f.Write([]byte("Hello World\n")); err != nil { // log.Fatal(err) // } else { // fmt.Println("All success") // } _, err := f.Write([]byte("Hello World\n")) if err != nil { log.Fatal(err) } else { fmt.Println("All success") } }
运行该代码:
$ go run main.go # command-line-arguments ./main.go:23:9: no new variables on left side of :=
所以发生了什么事?
请注意,我们使用 :=
调用 Write
,这意味着我们创建了一个新变量 err
。在第二个例子中,很明显,err
已经存在,所以我们不能重新声明它。
但是为什么它第一次起作用呢?因为在 Go 中,变量是其作用域的本地变量。在第一个示例中,我们实际上在 if
范围内隐藏了 err
。
例如:
package main func main() { var err error _ = err var err error _ = err }
这显然会失败,但是,如果我们限定第二个 err
,它会起作用!
package main func main() { var err error _ = err { var err error _ = err } }
包隐藏
考虑以下代码:
package main import "fmt" func Debugf(fmt string, args ...interface{}) { fmt.Printf(fmt, args...) }
起初,它看起来不错。我们从 fmt
包中调用 Printf
并将 fmt
变量传递给它。
函数声明中的 fmt
字符串实际上隐藏了包,现在“只是”一个变量。编译器会抱怨:我们需要使用不同的变量名来保存对 fmt
包的访问。
全局变量
需要考虑的是,一个函数已经是一个“子作用域”,它是全局作用域内的一个作用域。这意味着您在函数中声明的任何变量都可以在全局范围内隐藏某些内容。
正如我们之前看到的,变量可以映射包,全局变量和函数的概念是相同的。
类型强制
就像我们可以用变量或函数来映射一个包一样,我们也可以用任何类型的新变量来映射一个变量。阴影变量不需要来自同一类型。这个例子编译得很好:
package main func main() { var a string _ = a { var a int _ = a } }