Go 语言入门很简单:Go 中的作用域和变量隐藏(上)

简介: 变量隐藏在 Go 中可能会令人困惑,让我们尝试弄清楚。

网络异常,图片无法展示
|

变量隐藏在 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 函数创建了两个变量:ferr。然后我们调用 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
  }
}
相关文章
|
2天前
|
存储 Go 索引
go语言使用for循环遍历
go语言使用for循环遍历
16 7
|
5天前
|
存储 Go
go语言 遍历映射(map)
go语言 遍历映射(map)
18 2
|
6天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
6天前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
14 3
|
6天前
|
测试技术 Go 索引
go语言通过 for 循环遍历
go语言通过 for 循环遍历
16 3
|
Go 索引
Go实战(二)-变量、语句、函数、指针、关键字(下)
Go实战(二)-变量、语句、函数、指针、关键字
112 0
Go实战(二)-变量、语句、函数、指针、关键字(下)
|
Go
Go实战(二)-变量、语句、函数、指针、关键字(中)
Go实战(二)-变量、语句、函数、指针、关键字
100 0
Go实战(二)-变量、语句、函数、指针、关键字(中)
|
Go
Go实战(二)-变量、语句、函数、指针、关键字(上)
Go实战(二)-变量、语句、函数、指针、关键字
114 0
Go实战(二)-变量、语句、函数、指针、关键字(上)
|
16天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
26 2
|
2天前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。