共计 2437 个字符,预计需要花费 7 分钟才能阅读完成。
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 站账户 – 老麦胖熊猫 订阅最新文章和更多精彩内容