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语言中的变量、常量、数据类型
【11月更文挑战第3天】
39 9
|
2月前
|
存储 设计模式 安全
Go语言中的并发编程:从入门到精通###
本文深入探讨了Go语言中并发编程的核心概念与实践技巧,旨在帮助读者从理论到实战全面掌握Go的并发机制。不同于传统的技术文章摘要,本部分将通过一系列生动的案例和代码示例,直观展示Go语言如何优雅地处理并发任务,提升程序性能与响应速度。无论你是Go语言初学者还是有一定经验的开发者,都能在本文中找到实用的知识与灵感。 ###
|
2月前
|
Serverless Go
Go语言中的并发编程:从入门到精通
本文将深入探讨Go语言中并发编程的核心概念和实践,包括goroutine、channel以及sync包等。通过实例演示如何利用这些工具实现高效的并发处理,同时避免常见的陷阱和错误。
|
3月前
|
安全 Go 开发者
破译Go语言中的并发模式:从入门到精通
在这篇技术性文章中,我们将跳过常规的摘要模式,直接带你进入Go语言的并发世界。你将不会看到枯燥的介绍,而是一段代码的旅程,从Go的并发基础构建块(goroutine和channel)开始,到高级模式的实践应用,我们共同探索如何高效地使用Go来处理并发任务。准备好,让Go带你飞。
|
4月前
|
Go
Go to Learn Go之作用域
Go to Learn Go之作用域
32 5
|
3月前
|
存储 安全 Go
Go语言切片:从入门到精通的深度探索###
本文深入浅出地剖析了Go语言中切片(Slice)这一核心概念,从其定义、内部结构、基本操作到高级特性与最佳实践,为读者提供了一个全面而深入的理解。通过对比数组,揭示切片的灵活性与高效性,并探讨其在并发编程中的应用优势。本文旨在帮助开发者更好地掌握切片,提升Go语言编程技能。 ###
|
Java 编译器 Go
一起学Golang系列(五)初次接触Go语言可能遇到的各种坑!
前面介绍了Go语言的基础语法,所谓磨刀不误砍柴工,希望大家还是能熟悉掌握这些基础知识,这样后面真正学起Go来才会得心应手。 作为初学者。Go语言的语法有些和java类似,但也有很多不一样的地方。刚开始都会遇到各种各样的坑。下面就来总结下学习go语言的过程中,遇到的各种坑。
一起学Golang系列(五)初次接触Go语言可能遇到的各种坑!
|
19天前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
63 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
1月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
43 7
|
1月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。