乐趣区

关于后端:Golang-Block-到底是什么-ii-合法-为什么能解决闭包变量冲突

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

  1. 大括号 {} 突围的一个代码块。
  2. 这个代码块内容也能够为空,也能够是有内容。
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。这个其实还是有点意思的。

目前发现景象,

  1. test 文件 filename_test.go 中的 变量 / 函数 ,在 主程序文件 filename.go 中是无奈援用的。
  2. 主程序文件 中的 ` 变量 / 函数test 文件 中是无奈援用的。
  3. test 文件 之间的是能够相互援用的。
  4. 主程序 之间的是能够相互援用的。

因而揣测(无实锤),1. 存在 file block。2. 并且有高下等级之分。

其实很好了解,_test 是用于测试的,必定不能烦扰骨干程序的的环境。

留神 : 图片中是两个文件,上 main_test.gomain.go。并且 编译器 很显著的提醒了,在 main.go 中找不到变量 VarInTest

4. for, if, switch 的隐式 block

Each “if”, “for”, and “switch” statement is considered to be in its own implicit block.

  1. for, if, switch 自身是一个 隐式的 block
  2. 其语法中的 大括号 {} 所突围的区域是一个 显式的 Block
  1. for block (19-26 行) 自身就是一个 隐式的 block
  2. for 大括号 {} 局部(20-25 行) 的 是一个 显式的 block,作为 for block子 block (statement block) 存在

因而,在 22 行 i:=i 是非法的,statement block 中产生了 同名变量笼罩

也就是因为 {} 是 for 子 block 的起因,for 的 post 能够批改变量 i,在 statement 中也能够批改变量 i

  1. 因而,在 35 行被正文的时候,for block 的变量 i 被继承,并在 if block 中被批改,所以后果是 loop: 0,1,2,9
  2. 当 35 行存在的时候,for block 中的变量 istatement block 继承,并进行 同名笼罩 , 之后以 _i 阐明。所以,在 if block 继承了 statement block 中的 _i 并批改。此时,for blocki 并未受到影响。因而后果是: loop: 0-9
5. switch / selectclause 的 隐式 block

Each clause in a “switch” or “select” statement acts as an implicit block.

  1. switch / select 更为非凡一点,除了蕴含 大括号 以外,还蕴含条件语句逻辑。并且 条件语法代码块 也是一个 隐式的 block
  2. 这个 隐式 block 蕴含了 case / default: 自身之外,还蕴含了 下一层的缩进 Statement 区域
  1. 正文 20 行,能够很分明的看到报错,func block 中的 i 在申明后并未应用。此阐明了 switch 自身是一个 隐式 block。
  2. switch clause 分支 整体 (case 10-14 行)/(default 15-17) 是一个 block。

相互吹捧,共同进步

欢送和我一起学习提高,如果有什么问题,能够给我私信留言。或者

  1. 加我好友 线下探讨。
  2. 关注我的 公众号 – 老麦胖熊猫 或者 B 站账户 – 老麦胖熊猫 订阅最新文章和更多精彩内容
退出移动版