Go - Block + Scope
Variable Shadowing
1 | package main |
Block
Explicit Block
大括号包裹
1 | func foo() { // Block 1 |
- Explicit Block 是包裹在
大括号
内部的声明和语句序列 - 如果一对大括号内没有任何声明和其它语句,为
空 Block
- Block 支持
嵌套
Implicit Block
无法通过大括号识别
Implicit Block | Desc |
---|---|
Universe Block | 所有的 Go 源码 都在这个隐式代码块中 |
Package Block | 每个 Go 包 都对应一个隐式包代码块这个包代码块包含了该包中所有的 Go 源码(分散在多个源文件中) |
File Block | 每个 Go 源文件 都对应着一个文件代码块如果 Go 包有多个源文件,就会对应多个文件代码块 |
Control statement(if / for / switch) | 每个控制语句都在自己的隐式代码块中控制语句的隐式代码块在其显式代码块的外面 |
switch 或者 select 的 case/default 子s句 | 每个子句都是一个隐式代码块 |
Scope
作用域
是针对标识符
的,不局限于变量
- 每个
标识符
都有作用域
- 即一个标识符在被
声明后
可以被有效使用
的源码区域
- 即一个标识符在被
- 作用域是一个
编译期
的概念- 编译器在编译过程中会对每个标识符的作用域进行检查
- 如果在标识符作用域外使用该标识符,编译报错
- 可以使用
代码块
的概念来划定标识符
的作用域
- 原则:声明在外层代码块中的标识符,其作用域包括
所有内层代码块
- 同时适用于
Explicit Block
和Implicit Block
- 原则:声明在外层代码块中的标识符,其作用域包括
Universe Block
开发者并不能声明 Universe Block 的标识符,因为这一区域是
Go
用于预定义标识符
预定义标识符
并不是关键字
,可以在内层代码块
中声明同名
的标识符
1 | package main |
1 | $ go build |
Package Block
包顶层
声明的常量
、变量
、类型
、函数(不包括方法)
对应的标识符的作用域是包代码块- 当 A 包导入 B 包后,A 包仅可以使用 B 包的导出标识符(Exported Identifier)
- Exported Identifier
- 标识符声明在包代码块中,或者是一个
字段名
或者函数名
- 第一个字符是
大写的 Unicode 字符
- 标识符声明在包代码块中,或者是一个
File Block
导入的包名
属于 File Block - 如果 A 包有两个源码文件,都依赖了 B 包的标识符,那么两个源码文件都需要导入 B 包
Control statement
if
1 | func main() { |
将 Implicit Block 等价转换为 Explicit Block
1 | func main() { |
变量是标识符的一种,因此
标识符的作用域规则
同样适用于变量
规避遮蔽
内层变量遮蔽外层同名变量
1 | package main |
1 | $ go run main.go |
静态检查(
辅助
检测)
go vet
可以对 Go 源码进行一系列的静态检查
Go 1.14 之前
,默认支持变量遮蔽检查
,在 Go 1.14 之后,需要单独安装插件
来进行
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.