Hi,你们好,我是明哥。python
在本身学习 Golang 的这段时间里,我写了详细的学习笔记放在个人我的微信公众号 《Go编程时光》,对于 Go 语言,我也算是个初学者,所以写的东西应该会比较适合刚接触的同窗,若是你也是刚学习 Go 语言,不防关注一下,一块儿学习,一块儿成长。git
个人在线博客:golang.iswbm.com 个人 Github:github.com/iswbm/GolangCodingTimegithub
因为 Go 使用的是词法做用域,而词法做用域依赖于语句块。因此在讲做用域时,须要先了解一下 Go 中的语句块是怎么一回事?golang
通俗地说,语句块是由花括弧({}
)所包含的一系列语句。shell
语句块内部声明的名字是没法被外部块访问的。这个块决定了内部声明的名字的做用域范围,也就是做用域。编程
用花括弧包含的语句块,属于显示语句块。数组
在 Go 中还有不少的隐式语句块:bash
前面三点好理解,第四点举几个例子微信
for 循环完后,不能再使用变量 i 编程语言
for i := 0; i < 5; i++ {
fmt.Println(i)
}复制代码
if 语句判断完后,一样不能再使用变量 i
if i := 0; i >= 0 {
fmt.Println(i)
}复制代码
switch 语句完了后,也是否是再使用变量 i
switch i := 2; i * 4 {
case 8:
fmt.Println(i)
default:
fmt.Println(“default”)
}复制代码
且每一个 switch 语句的子句都是一个隐式的语句块
switch i := 2; i * 4 {
case 8:
j := 0
fmt.Println(i, j)
default:
// "j" is undefined here
fmt.Println(“default”)
}
// "j" is undefined here复制代码
变量的声明,除了声明其类型,其声明的位置也有讲究,不一样的位置决定了其拥有不一样的做用范围,说白了就是我这个变量,在哪里可用,在哪里不可用。
根据声明位置的不一样,做用域能够分为如下四个类型:
以上的四种做用域,从上往下,范围从大到小,为了表述方便,我这里本身将范围大的做用域称为高层做用域,而范围小的称为低层做用域。
对于做用域,有如下几点总结:
在这里要注意一下,不要将做用域和生命周期混为一谈。声明语句的做用域对应的是一个源代码的文本区域;它是一个编译时的属性。
而一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间区域内它能够被程序的其余部分引用;是一个运行时的概念。
根据局部做用域内变量的可见性,是不是静态不变,能够将编程语言分为以下两种:
具体什么是动态做用域,这里用 Shell 的代码演示一下,你就知道了
#!/bin/bash
func01() {
local value=1
func02
}
func02() {
echo "func02 sees value as ${value}"
}
# 执行函数
func01
func02复制代码
从代码中,能够看到在 func01 函数中定义了个局部变量 value,按理说,这个 value 变量只在该函数内可用,但因为在 shell 中的做用域是动态的,因此在 func01中也能够调用 func02 时,func02 能够访问到 value 变量,此时的 func02 做用域能够当成是 局部做用域中(func01)的局部做用域。
但若脱离了 func01的执行环境,将其放在全局环境下或者其余函数中, func02 是访问不了 value 变量的。
因此此时的输出结果是
func02 sees value as 1
func02 sees value as 复制代码
但在 Go 中并不存在这种动态做用域,好比这段代码,在func01函数中,要想取得 name 这个变量,只能从func01的做用域或者更高层做用域里查找(文件级做用域,包级做用域和内置做用域),而不能从调用它的另外一个局部做用域中(由于他们在层级上属于同一级)查找。
import "fmt"
func func01() {
fmt.Println("在 func01 函数中,name:", name)
}
func main() {
var name string = "Python编程时光"
fmt.Println("在 main 函数中,name:", name)
func01()
}复制代码
所以你在执行这段代码时,会报错,提示在func01中的name还未定义。
参考文章:studygolang.com/articles/12…
系列导读
24. 超详细解读 Go Modules 前世此生及入门使用