分类 技术志 下的文章

对一段有关Go Code Block和变量作用域的代码的简要分析

近期,Go team的David CrawShawtwitter上贴出了一段代码,如下:

func main() {
    if a := 1; false {
    } else if b := 2; false {
    } else if c := 3; false {
    } else {
        println(a, b, c)
    }
}

David CrawShaw想表达的意图是gopher们很少在”else if”后面的simple statement中使用“短变量声明”形式,而这段代码是个例外。我们看到b、c两个变量都是在else if 的simple statement中使用短变量声明形式定义的。

我个人看到这段代码后,第一反应是:这段代码能编译运行吗?else语句中的“println(a, b, c)”是否会被compiler报出:undefined b, c的错误呢?不知道是否有其他的gopher们与我有同样的反应:)。无论怎样,既然有了疑问,我们就应该把它分析清楚。

一. Go代码块和作用域简介

根据Go语言的规范,我们知道Go的标识符作用域是基于代码块(code block)的。代码块就是包裹在一对大括号内部的声明和语句,并且是可嵌套的。我们在代码中直观可见的显式的(explicit)code block有很多,比如:函数的函数体、for循环的循环体等:

func Foo() {
    // here:显式的(explict block)代码块,包裹在函数的函数体内
   ... ...

    for {
            // here: 显式的(explict block)代码块,包裹在for循环体内
            // 该代码块就嵌套在函数体这个代码块的内部
        ... ...
    }
}

但除了显式explict的code block,Go语言中还有几种隐式的(implicit)代码块,它们都是什么呢?这里摘录下go spec原文(不翻译了):

1. The universe block encompasses all Go source text.
2. Each package has a package block containing all Go source text for that package.
3. Each file has a file block containing all Go source text in that file.
4. Each "if", "for", and "switch" statement is considered to be in its own implicit block.
5. Each clause in a "switch" or "select" statement acts as an implicit block.

我们看到if语句会引入一个隐式的code block,这为我们后续的分析奠定了基础。

二. if语句的code block

那么if语句的code block详细情况如何呢?我们分门别类地简单看看:

1. if _ 型

我们使用最多的if语句类型就是单if型,即:

if simplestmt; expression {
    ... ...
}

在这种类型的if语句中,有两个code block:一个隐式的code block和一个显式的code block。我们把上面的形式代码做一个等价变化,并加上code block起始和结束点的标注,结果如下:

{ // implicit block begin
    simplestmt

    if expression { // explicit block begin
            ... ...
    } // explicit block end

} // implicit block end

我们看到if后面的”大括号对”引入的explict code block嵌套在if simplestmt所在的implicit code block内部,这也是为何simplestmt中用短声明形式定义的变量在explict block中可以使用的原因:

func main() {
    if a := 1; true {
        fmt.Println(a) // output: 1
    }
}

2. if _ else _ 型

我们再来看看if _ else _ 型

if simplestmt; expression {
    ... ...
} else {
    ... ...
}

分析逻辑同上,我们将上面的伪代码做一个等价变换,并作出code block起始结束点标注:

{ // implicit block begin
    simplestmt

    if expression { // explicit block1 begin
            ... ...
    }  else  { // explicit block1 end, explicit block2 start
            ... ...
    } //explicit block2 end

} // implicit block end

我们看到if _ else _ 型 有三个code block,除了单if型的两个block外,还由else引入一个explict code block(即上面代码中的explict block2)。

3. if _ else if _ else _ 型

最后我们来看看最为复杂的if _ else if _ else _ 型

if simplestmt1; expression1 {
    ... ...
} else if simplestmt2; expression2 {
    ... ...
}  else {
    ... ...
}

我们依旧将上面的伪代码做一个等价变换,并作出code block起始结束点标注,结果如下:

{ // implicit block1 begin
    simplestmt1

    if expression { // explicit block1 begin
            ... ...
    }  else  { // explicit block1 end, explicit block2 start

            {  // implicit block2 begin
                simplestmt2

                if expression2 { //  explicit block3 start

                } else { // explicit block3 end, explicit block4 start

                } // explicit block4 end

            } // implicit block2 end

    } //explicit block2 end

} // implicit block1 end

我们看到在该类型下,我们一共识别出两个implict block和四个explict block。

三. 对David CrawShaw贴出的那段代码的分析

有了第二节的基础,再来看David CrawShaw的这段代码:

func main() {
    if a := 1; false {
    } else if b := 2; false {
    } else if c := 3; false {
    } else {
        println(a, b, c)
    }
}

依照我们的思路,我们可以对这段代码做一个等价变化:

func main() {
    {
        a := 1
        if false {

        } else {
            {
                b := 2
                if false {

                } else {

                    {
                        c := 3
                        if false {

                        } else {
                            println(a, b, c)
                        }
                    }
                }
            }
        }
    }
}

展开后的语句就很是一目了然了,不用说什么大家也会很清楚了。最重要的一点是原来代码中最后的那个else实际上是与最内层的else if配对的,而不是与最开始的if配对的,因此println(a, b, c)的时候,a, b, c三个变量都是已经声明定义了的(在外层的code block中)。

对于此类涉及code block或变量作用域的问题,还可以通过go vet -shadow工具来辨别,或通过go run执行后的出错信息来辨别,这里就不详细说明了。

四. 参考资料


51短信平台:企业级短信平台定制开发专家 https://51smspush.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

我的联系方式:

微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

慕课网免费课“Kubernetes:开启云原生之门”上线

这两年一直在做一个基于Kubernetes的、用于互联网产品运营支撑的类PaaS平台,因此一直把自己定位为一个Kubernetes实践者:以Kubernetes为中心进行集群搭建、运维、k8s相关技术的理解与应用、k8s新技术的追踪和尝试落地等。不过就Kubernetes的深入程度来说,感觉自己和那些天天与k8s打交道的大厂专家或以容器云为卖点的技术专家还是有差距的。但是大厂专家每周996,闲暇时间不多,这让他们无暇系统化地传道受业解惑,而我却有一些闲暇时间来写写有关Kubernetes的知识和经验。于是在春节前,一次机缘巧合,和慕课网“勾搭上了”并达成一致:在慕课网做一门有关Kubernetes的课程。

按照慕课网的要求,我要先上一门有关Kubernetes的免费公开课。于是经过“漫长”的录制和制作后,我的第一门在线网课《Kubernetes:开启云原生之门》于今天在慕课网正式上线了。

**课程链接:https://www.imooc.com/learn/978 **

img{512x368}

一. 课程介绍

先来简单介绍一下这门不到2小时的免费课程

容器技术和Kubernetes重新定义了现在以及未来十年基础设施承载云原生应用的形式,作为CNCF基金会下面的首席托管项目,Kubernetes在2017年击败swarm和mesos,成为了容器管理与调度编排领域的首选平台和事实标准。今年年初,CNCF又宣布Kubernetes正式毕业,标志着Kubernetes作为一个开源项目已经成熟,并且具有足够的韧性,可以在任何行业和各种规模的公司的生产环境中大规模应用了。Kubernetes存在的意义还不仅仅局限于容器编排解决方案,其最终使命应该是成为云计算时代的新一代应用上云的首选平台,成为支撑云原生应用部署运行的新一代”云平台”。

对于普通开发人员来说,Kubernetes虽然结构简单,但规模“庞大”,所涉技术与生态圈外延较广,学习曲线较为陡峭。我的这门基础课就定位于帮助大家降低学习门槛,打开通往k8s平台支撑的云原生的大门的

这门课程共分为五个部分。

第一部分:了解一下应用部署运行模式的变迁历史,弄清楚每种应用部署运行模式的特点、对开发者的影响以及模式演进的趋势。
第二部分:了解Kubernetes究竟是什么? 我们为什么要使用Kubernetes,它能给开发者带来哪些好处?
第三部分:实际操作如何在Kubernetes集群上部署和管理一个应用。
第四部分:学习一下Kubernetes的架构、组件以及组件功用。
第五部分:以Kubernetes对象模型为主线,一起来学习一下Kubernetes的基本概念。

通过这门课程的学习,我期望大家能掌握如下知识和技能:

1、Kubernetes是什么?
2、为什么要使用Kubernetes? Kubernetes给开发者带来哪些好处?
3、如何在Kubernetes集群上部署和管理一个应用
4、Kubernetes的架构
5、Kubernetes的组件与功用
6、Kubernetes对象模型以及基础概念

课程针对的对象也很宽泛,对于那些对容器、Kubernetes感兴趣的开发、测试、运维人员;架构师和技术决策者;技术爱好者都可以观看一下该课程视频。同时,这个课程也将起到“承上启下”的作用,为后续在慕课网的Kubernetes实战课(录制中)做铺垫。

二. 录课心得

这是我第一次录网课,完全没有经验可谈。还好在录课准备期间,慕课网的胡老师给予我很专业的支持。

作为网课讲师,首先要做的其实是学习,即按照委托方对课程的要求,进行ppt结构与形式制作(按照模板)、音视频基础剪辑等方面的学习。一定的剪辑技能可以让你在录制过程中减少很多重复录制,节省不少的精力和时间。

其次,课程定位与内容规划。课程定位是首先要和委托方课程接口人做详细交流,达成一致的,要明确课程难度级别、课程受众对象以及课程的内容重点。内容规划就基本上是你的专业领域的事情了,当然委托方教学接口人会根据他的经验给予你有关课程内容规划的一些很好的建议。

最后就是录制过程了。录制过程其实是“很辛苦”的,要习惯于一个人长时间的独处。由于是利用业余时间录制并且有录制环境要求(至少是安静、无人打扰吧),一周下来其实满足条件的时间窗口并不多。我个人基本上是工作日晚上准备录制脚本、环境和demo例子,周末两天集中录制。录制脚本这块我没有什么诀窍,我的笨招就是将要表述的都写到一个文件中,像台词一样在录制的时候读出来。这样可以保证每段视频是可以被Reproduce的:)。那些实际操作的演示环节,也会按照之前列出的要点进行。

所以录制的这段时间内,基本上是没有周末的,都是待在家里不出门。即便有事的时候,比如陪着孩子去上补习班时,我也是带着笔记本的,编写一些录制脚本或优化一些台词。

三. 小结

应用上云,以前都是考虑虚拟机、OpenStack之类的技术栈,现在是时候考虑Kubernetes了。并且在面向容器化应用、云原生应用开发和运维方面,一批旨在降低开发难度、改善开发体验的开源项目正在兴起,比如号称云原生应用标准库的metaparticle-io、CoreOS的operator framework等。

即便你不会亲手搭建和运维Kubernetes集群,而仅仅是使用现成的基于k8s的容器云服务,那么通过本门课程了解一下Kubernetes的基础知识也是大有裨益的。说不定将来”kubernetes first”或”kubernetes-oriented”会成为时髦的技术词汇。

由于是第一次录制网课,在声音和表达技巧方面显得都不够专业,还望理解。同时也欢迎各位小伙伴针对这门课程参与交流讨论,多提宝贵建议和意见。

最后,感谢慕课网胡老师对本门课程的耐心和专业指导。


我爱发短信:企业级短信平台定制开发专家 https://51smspush.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

我的联系方式:

微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats