《Effective Ruby:改善Ruby程序的48条建议》一第5条:留意运行时警告-阿里云开发者社区

开发者社区> 华章出版社> 正文

《Effective Ruby:改善Ruby程序的48条建议》一第5条:留意运行时警告

简介:

本节书摘来自华章出版社《Effective Ruby:改善Ruby程序的48条建议》一书中的第1章,第1.5节,作者[美]彼得 J.琼斯(Peter J. Jones),更多章节内容可以访问云栖社区“华章计算机”公众号查看

第5条:留意运行时警告

Ruby程序员喜欢在书写、执行以及测试代码时使用短周期的反馈模式。Ruby中使用解释执行的方式运行代码,因此并不存在编译阶段。否则怎样?假如你仔细想想,Ruby一定会做些和编译器所做的相同的事情,比如解析你的源代码。当你的代码交给解释器时,它不得不做些编译,比如执行代码之前的一些任务。思考Ruby执行代码的两个步骤是有帮助的:编译阶段和运行阶段。
解析和理解代码发生在编译阶段,执行代码发生在运行阶段。在你思考Ruby产生的各类警告时,两个阶段的差别尤其重要。编译阶段产生的警告往往和要使Ruby正常运行所需的语法问题有关。而运行时的警告则能指出粗糙的程序中可能潜藏的错误。留意运行时的警告可以帮助我们在错误的代码变成真正的问题之前将其修复。在谈论如何启用Ruby的各种警告之前,让我们先探索一下常见的警告消息以及产生它们的原因。
特别需要留意编译阶段产生的警告。它们中的多数是由于Ruby遇到含混不清的语法和多种可能的解释时产生的。你显然不想让Ruby猜到你真的想要做什么。如果Ruby的一个未来的版本改变了对模糊代码的理解模式,想象一下会发生什么呢?你的代码会表现出完全不同的行为。既然如此,你完全可以留意这些类型的警告,做出必要的更改,从而在开始处就避免模糊的代码。这里有个例子,可以说明Ruby遇到不清晰的代码并产生警告:
image

当Ruby解析器遇到第一处反斜杠时,它需要确定这是一个正则表达式文法的开始还是一个除号。在本例中,将其假设为正则表达式的开始是非常合理的,它应该作为split方法的第一个参数。不过也很容易看出,它可以被解释为除号,split命令的输出作为左操作数。警告本身很普通,并且只有一半是有用的。但是修复这个问题足够容易——使用括号:
image

假如你交给Ruby代码时启用了警告选项,那么你可能看到其他和操作数以及括号相关的警告。原因几乎都是相同的:Ruby不能完全肯定你的意图并选择最合理的解释。不过再问一次,你真的希望Ruby猜出你的意图或者说在一开始你就完全清楚你的意图吗?下面两个例子可以说明通过为参数增加括号来修复不清晰的方法调用。
image

其他在编译阶段有用的警告就和变量有关了。比如,如果你为变量赋值却没有使用它,Ruby就会警告你。这可能意味着你浪费了一些内存,但更可能意味着你在计算中忘了包含它的值。如果你在同一作用域创建了两个命名相同的变量,你也会收到警告,这种警告被称为变量隐藏(ariable shadowing)。当你定义一个块变量时,而在同一作用域中已经定义了相同名字的变量,这种警告就会产生。这两种变量警告都可以在下面的例子中看到:
image

如你所见,这些编译阶段的警告并非真意味着你做错了什么,但是有这种可能性。
因此最好的行动就是检查这些警告并相应地对源代码进行更改。对代码执行或者说运行时产生的警告我会说同样的话。这些警告仅会在代码执行一些可疑操作之后被检测到,比如,访问未初始化的实例变量或者重定义已存在的方法。这两种情况都可能是故意或意外出现的。如其他警告一样,这些都很容易修复。
我想你已经明白了,因此我不再枚举更多的、描述性的、容易修复的运行时警告。作为替代,我想讲讲如何在开始就启用这些警告。再说一次,区别编译阶段和运行阶段的警告很有必要。如果你希望Ruby在你的代码被解析时产生警告,你需要确保启用解析器警告标记。这非常容易,只需要运行Ruby时加上“-w”命令行选项。
image

但对有些应用程序并非如此简单。也许你的Ruby程序是通过Web服务器或后台运行的任务自动启动的,或者更普遍,你希望使用Rake这样的工具在运行测试时启动警告。当你不能通过使用命令行选项“-w”告诉解释器你希望启用警告选项时,你可以直接通过设置环境变量RUBYOPT来实现它。如何设置环境变量则取决于你的操作系统以及程序启动方式。最重要的是,在你的应用程序运行环境中,设置环境变量RUBYOPT为“-w”这个事件必须发生在Ruby启动之前。
(我也得提一下,如果你正使用Rake来运行测试,你还有一种方式来启用警告选项。第36条包含了一个Rakef?ile的例子,演示了这种方式。)
现在,还有最后一种方式来启用警告。文档很少提及,因此经常引起很多困惑。在你的程序中,你能够查看和操作全局变量$VERBOSE(它的别名是$-w)。如果你想看到所有可能的警告消息,你应该将其设为true。将其值设为false会减少显示的信息(产生更少的警告),而设为nil则会禁用警告。你可能会想,“嘿,如果我把$VERBOSE设置为true,那我就不需要浪费时间在‘-w’的事情上了。”这是编译阶段和运行阶段的区别真正给我们的帮助。
假如你运行Ruby解释器时不加“-w”选项,而是使用变量$VERBOSE,那你将看不到编译时警告。因为全局变量$VERBOSE只到程序运行时才会被设置。那时,解析阶段已经结束了,你当然就错过了编译阶段的警告。因此,可以遵循以下两条指导方针。其一,启用编译阶段的警告可以通过在运行Ruby解释器时使用命令行选项“-w”,或通过设置环境变量RUBYOPT为“-w”。其二,控制运行时的警告可以使用全局变量$VERBOSE。
我的建议是,在应用程序的开发阶段始终启用编译时和运行时的警告。如果必须禁用运行时警告,那么可以临时将全局变量$VERBOSE设置为nil。
很遗憾,启用警告消息本身会触发一个警告。让人失望的还有,启用警告这件事情并不是常见的做法。因此,如果你使用了RubyGems并启用了警告,可能会收到很多源于它们的警告。这将很可能导致你禁用警告。还好,Ruby打印警告到命令窗口时会包含警告相应的文件名和行号,因此写点脚本来过滤掉这些无关警告是很容易的。你甚至可以做得更好,以一个优秀的开源代码贡献者的身份,提交代码去修复这种有点粗糙又存在警告的gems。
要点回顾
使用命令行选项“-w”来运行Ruby解释器以启用编译时和运行时的警告。设置环境变量RUBYOPT为“-w”也可以达到相同目的。
如果必须禁用运行时的警告,可以临时将全局变量$VERBOSE设置为nil。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接