《Effective Ruby:改善Ruby程序的48条建议》一第4条:留神,常量是可变的

简介:

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

第4条:留神,常量是可变的

如果你学习Ruby之前学过其他的编程语言,Ruby中常量的行为很可能和你预料的不同。不过,在深挖之前让我们回顾一下在Ruby中什么是常量。
当你初次学习Ruby时,可能有人教你,说常量是由大写字母和下划线组成的标识符。一些例子包括STDIN、ARGV以及RUBY_VERSION。不过这不是故事的全部。事实上,由大写字母开头的任何标识符都是常量。这表示String或Array也都是常量。没错,就是这样……Ruby中那些类和模块的名字事实上都是常量。记着这些,让我们来深入了解在Ruby中常量和其他看似变量的东西有什么区别。
正如其名字建议的那样,常量原打算在程序的生命周期中保持不变。因此,你可能假设Ruby会阻止你改变常量的值的行为。好吧,你的假设是错的。来看看这个:
image

如果调用方法unreachable时没有加参数的话,就会意外地改变一个常量的值。在Ruby中这样做甚至都不会警告你。本质上讲,Ruby中的常量相比不变值来说更像是全局变量。假如你仔细想想,既然类和模块名都是常量,那么你可以在任何时候改变一个类(比如增加些方法),引用类的那些对象也会随之变化。这些对类和模块来说都没有问题,不过对那些我们真正希望是不变量的常量来说就不那么美好了。还好,有一种解决这个问题的方法——freeze方法:
image

适当地做以上变化,假如再想改变常量NETWORKS的值时,purge_unreachable方法就会引发RuntimeError异常。根据一般的经验,总是通过冻结常量来阻止其被改变。然而不幸的是,冻结NETWORKS数组还不够,来看看这个:
image

如果第二个参数没有赋值,那么host_addresses方法会修改数组NETWORKS的元素。即使数组NETWORKS自身被冻结,但其元素仍然是可变的。你可能无法从数组中增删元素,但你一定可以对存在的元素加以修改。因此,如果一个常量引用了一个集合,比如数组或是散列,那么请冻结这个集合以及其中的元素:
image

(如果你恰巧使用了Ruby 2.1或更高版本,你可以使用第47条中的小技巧直接冻结字符串的字面量。这可以在防止元素被意外改变的同时节省一些内存。)
冻结常量可以把一个隐晦的、难以发现的问题变成一个异常。这显然是很好的。然而,这还不够。即使冻结了一个变量所指向的对象,你仍然会在给存在的常量赋予新值时引发问题。不信请看这个例子:
image

如你所见,在Ruby中给存在的常量赋予新值是完全合法的。你也看到Ruby产生了警告,说我们正在改变一个常量的值。不过仅此而已。还好,如果我们自己处理这些事情,可以让Ruby在我们意外地重定义常量时引发异常。不过这个解决方案有些笨拙,并且在某些时候显得有些粗暴,但胜在简单。要防止Ruby为常量重新赋值,可以冻结常量所在的类或者模块。你甚至可能会想结构化你的代码,从而将所有常量都定义在它们各自的模块中,从而隔绝freeze方法的影响。
image

定义常量时,你可以考虑在三个级别进行冻结。前两个比较简单:冻结常量引用的对象以及定义常量的模块。这两步防止了常量被改变和重新赋值。第三种则有些复杂。我们看到,如果常量引用了一个字符串数组,我们就需要冻结这个数组以及其所有元素。换句话说,需要深层冻结该常量引用的这个对象。每个常量都会有所不同,我们只需保证它被完全冻结就可以了。
要点回顾
总是将常量冻结,从而防止其被改变。
如果常量引用了一个集合对象比如数组或散列,那么冻结这个集合及其所有
元素。
要防止常量被重新赋值,可以冻结定义它的那个模块。

相关文章
|
10月前
|
缓存 监控 数据库
使用Ruby构建可扩展的Web应用程序
在当今科技驱动的世界中,Web应用程序成为了企业和个人进行业务活动、提供服务和与用户互动的重要方式。而Ruby作为一种简洁、优雅且易于学习的编程语言,已经成为许多开发者的选择。本篇博客将介绍如何使用Ruby构建可扩展的Web应用程序。
83 0
|
Java 程序员 数据安全/隐私保护
【Ruby高级技术】对面向对象里的控制访问,包括类的继承类常量的深入理解和使用
【Ruby高级技术】对面向对象里的控制访问,包括类的继承类常量的深入理解和使用
106 1
|
测试技术 C++ Ruby
C++程序中嵌入Ruby脚本系统
Ruby,一种为简单快捷面向对象编程(面向对象程序设计)而创的脚本语言,由日本人松本行弘(まつもとゆきひろ,英译:Yukihiro Matsumoto,外号matz)开发,遵守GPL协议和Ruby License。
1582 0
|
消息中间件 安全 Ruby
Nanite:Ruby程序的一个自我装配集群
本文讲的是Nanite:Ruby程序的一个自我装配集群,Nanite(由Ezra Zygmuntowicz开发)是Engine Yard云计算策略的一个新兵:它是“Ruby程序的一个自我装配集群”,用以构筑高度可伸缩的Web应用的后端。
1103 0
|
程序员 Ruby
《Effective Ruby:改善Ruby程序的48条建议》一导读
学习一门新的编程语言通常需要经过两个阶段。第一阶段是学习这门编程语言的语法和结构。如果我们具有其他编程语言的经验,这个阶段通常只需要很短的时间。以Ruby为例,接触过其他面向对象语言的程序员对Ruby的语法也会比较熟悉。有经验的程序员对于语言的结构(如何根据语法构建应用程序)是很熟悉的。
1216 0
|
C语言 C++ Ruby
编译c语言程序扩展ruby
环境: windows 10 64bit ruby 2.2.4p230 (2015-12-16 revision 53155) [i386-mingw32] gcc version 4.8.
1047 0
|
Ruby
Ruby对象、变量和常量
Ruby操作的数据主要有部分:对象、类、变量、常量. 对象 在Ruby中表示数据的基本单位称为对象,在Ruby中一切都是对象.
548 0
|
Web App开发 Ruby
第一个Ruby On Rails WEB应用程序HelloWorld
经过不懈努力终于把Ruby On Ralis 的开发环境搭建好了,在WIN7系统下,赶紧来个最最常用的例子来练练手吧,感受一下Ruby。。。 再次声明一下,我的ruby -v是ruby-2.0.0p247。
1272 0
|
NoSQL 数据库 Ruby
我的第一个Ruby On Rails + MongoDB程序
    最近想进一步学习一下MongoDB,而很久之前使用过ROR,正好也凑个机会重新拾起来。下面是建立第一个项目的过程。        主要参考文档:        1. Rails 3 - Getting started        2.
937 0