首页 > > > 从零学习 Go 语言(20):理解语句块与作用域

由于 Go 使用的是词法作用域,而词法作用域依赖于语句块。所以在讲作用域时,需要先了解一下 Go 中的语句块是怎么一回事?
通俗地说,语句块是由花括弧({})所包含的一系列语句。
语句块内部声明的名字是无法被外部块访问的。这个块决定了内部声明的名字的作用域范围,也就是作用域。
用花括弧包含的语句块,属于显示语句块。
在 Go 中还有很多的隐式语句块:
前面三点好理解,第四点举几个例子
for 循环完后,不能再使用变量 i
for i := ; i < 5; i++ {
fmt.Println(i)
}if 语句判断完后,同样不能再使用变量 i
if i := ; i >= {
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 :=
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还未定义。
参考文章:https://studygolang.com/articles/12632
http://weixin.qq.com/r/WzsLE2LE2T_mrSZw925J<br>http://weixin.qq.com/r/0i8xKdHERIw7rZVK93rA (二维码自动识别)
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/758/viewspace-3157568/ ,如需转载,请注明出处,否则将追究法律责任。