Golang Block 到底是什么? i:=i
非法? 为什么能解决闭包变量抵触?
什么? 你通知我 i:=i
不仅非法,而且还罕用。甚至能解决并发编程中的变量抵触?
以下这段代码出自 golang 官网
的 Effective GO
并发编程章节。 为了解决 goroute 中变量 req
抵触, 应用了语句 req := req
https://golang.org/doc/effective_go#concurrency
咱们来看看代码
func Serve(queue chan *Request) { for req := range queue { req := req // Create new instance of req for the goroutine. sem <- 1 go func() { process(req) <-sem }() }}
req := req
这种写法是不是感到很奇怪? 看看 Effective GO
怎么说?
but it's legal and idiomatic in Go to do this. You get a fresh version of the variable with the same name, deliberately shadowing the loop variable locally but unique to each goroutine.
不仅非法,而且还罕用。 这么做是为了在循环体外部将失去一个同名变量, 以暗藏 循环变量 req, 从而每个 goroute 失去一个惟一
req
。
间接这么看,还是有点拗口。 不过不重要, 在理解了 golang 的 区块(block) 定义范畴之后, 就迎刃而解了。
Blocks
https://golang.org/ref/spec#Blocks
A
block
is a possibly empty sequence of declarations and statements within matching brace brackets.
什么是 Blocks
?
- 用 大括号
{}
突围的一个代码块。 - 这个代码块内容也能够为空, 也能够是有内容。
Block = "{" StatementList "}" .StatementList = { Statement ";" } .
Block 的范畴在哪里?
除了咱们下面说的 以大括号{}
突围的代码块 这种 显式 block 之外, go 语言还存在几种 隐式 的 block。
1. universe
全局
The universe block encompasses all Go source text.
universe
这个词不怎据说, 然而换成 全局 这个概念还是很好了解的。
2. package
包
Each package has a package block containing all Go source text for that package.
package
就是最常见的 package
包。 作用域也很明确, 应用相似 package.Variable
。
3. file
文件
Each file has a file block containing all Go source text in that file.
文件级别的隐式 block
。 这个其实还是有点意思的。
目前发现景象,
- test文件
filename_test.go
中的 变量/函数 , 在 主程序文件filename.go
中是无奈援用的。 - 在 主程序文件 中的 ` 变量/函数 在 test文件 中是无奈援用的。
- test文件 之间的是能够相互援用的。
- 主程序 之间的是能够相互援用的。
因而揣测(无实锤), 1. 存在 file block
。 2. 并且有高下等级之分。
其实很好了解, _test
是用于测试的, 必定不能烦扰骨干程序的的环境。
留神: 图片中是两个文件, 上 main_test.go
下 main.go
。 并且 编译器 很显著的提醒了, 在 main.go
中找不到变量 VarInTest
。
4. for
, if
, switch
的隐式 block
Each "if", "for", and "switch" statement is considered to be in its own implicit block.
for
,if
,switch
自身是一个 隐式的 block- 其语法中的 大括号
{}
所突围的区域是一个 显式的 Block。
- for block (19-26 行) 自身就是一个 隐式的 block 。
- for 大括号
{}
局部(20-25行) 的 是一个 显式的 block , 作为for block
的 子 block(statement block)
存在
因而, 在 22 行 i:=i
是非法的, 在 statement block
中产生了 同名变量笼罩
。
也就是因为 {} 是 for 子block 的起因, for 的 post 能够批改变量 i, 在 statement 中也能够批改变量 i
- 因而, 在 35 行被正文的时候, for block 的变量 i 被继承,并在 if block 中被批改, 所以后果是
loop: 0,1,2,9
- 当 35 行存在的时候,
for block
中的变量i
被statement block
继承, 并进行 同名笼罩 , 之后以_i
阐明。 所以, 在if block
继承了statement block
中的_i
并批改。 此时,for block
的i
并未受到影响。 因而后果是:loop: 0-9
5. switch / select
中clause
的 隐式 block
Each clause in a "switch" or "select" statement acts as an implicit block.
switch / select
更为非凡一点, 除了蕴含 大括号 以外, 还蕴含条件语句逻辑。 并且 条件语法代码块 也是一个 隐式的 block。- 这个 隐式 block 蕴含了
case / default:
自身之外, 还蕴含了 下一层的缩进 Statement 区域 。
- 正文 20 行, 能够很分明的看到报错,
func block
中的i
在申明后并未应用。 此阐明了 switch 自身是一个 隐式 block。 switch clause 分支
整体 (case 10-14 行)/(default 15-17) 是一个 block。
相互吹捧, 共同进步
欢送和我一起学习提高, 如果有什么问题, 能够给我私信留言。 或者
- 加我好友 线下探讨。
- 关注我的 公众号 - 老麦胖熊猫 或者 B站账户 - 老麦胖熊猫 订阅最新文章和更多精彩内容