InfoQ

新闻

Ruby编程:清晰明确的代码还是简洁精炼的代码?

作者 Werner Schuster译者 Jason Lai 发布于 2007年7月30日 上午9时0分

社区
Ruby
主题
编程
标签
语言特性,
编码标准,
故障解决

Pier Cawley撰文探讨了他在一篇介绍延迟初始化属性的博客文章中发现的潜在问题。出现问题的代码如下:

def content
@content ||= []
end

这段代码的目的是为了支持类的延迟初始化属性。在这个例子当中,除非@content这个实例变量已经初始化完毕,否则在它的访问器方法content方法被调用的时候,它就会被初始化。||=这个操作符意思是“如果左边的变量值为nil,将它的值赋为右边表达式,否则仅返回左边的变量值。”

然而,Piers指出,对于某些值来说,这样做是会出现问题的,因为Ruby处理布尔值和nil的方式比较特殊。我们来看看下面这样一个例子:

a = false
a ||= "Ruby"

这样的代码结果是怎样的呢?由于a已经在第一行被初始化,第二行不应产生任何效果。然而,在代码执行之后,我们会发现a现在的值为"Ruby",而不是false

在熟记Ruby中编写nil检查通用方式之后,问题就变得非常显而易见:

if name
puts name.capitalize
end

在Ruby中,nil被解释成布尔值false,因此if子句中的代码只有在name的值不等于nil的时候才能运行。

尽管在通常意义上这不会成为一个问题,但是在延迟初始化属性的代码中,如果付给属性的合法值是nil或者false的时候,这就会成为一个问题。在这种情况下,对属性进行访问之后,属性值就会被重设成缺省值。

当然,这是一个边界情况,但是这样的问题会导致人们花很长时间进行调试,来试图找出到底为什么某些方法有些时候会被重设而另外一些则不会。

Piers为这段代码给出了一个条理更为清晰的代码

def content
unless instance_variable_defined? :@content
@content = []
end
return @content
end

这样,代码只会在变量还没有被定义的时候才会初始化变量。

通过这个小例子,我们可以把错误归咎于Ruby及其部分语言特性——但哪一类程序员会把错误归咎于工具而不是他们自身,这已经是众所周知的事实了。尽管Ruby代码的简洁性非常有用,但还是有一些情况下使用更加明确表达意图的表达式会更安全一些。在这个例子中,||=并非正确的解决方案,相反初始化代码应当检查变量是否已经被定义。

亲爱的读者,您在以前是否也被这样的问题敲中脑门呢?Ruby是否存在哪些你希望避免的语言特性,以预防上述难于发现的问题呢?

查看英文原文:Explicit vs. concise code in Ruby

相关赞助商

InfoQ中文站Ruby社区,面向Web和企业开发的Ruby,主要关注Ruby on Rails,通过新闻、文章、视频访谈和演讲以及迷你书等为中国Ruby社区提供一流资讯。

5 条回复

回复

这个陷阱不具通用性 发表人 松 刘 发表于 2007年7月30日 上午8时14分
ruby就是太灵活了 发表人 立 张 发表于 2007年7月30日 上午8时16分
并非陷阱 发表人 li fei 发表于 2007年7月30日 下午7时56分
Re: 并非陷阱 发表人 gpy good 发表于 2007年7月31日 下午10时1分
我不认为这是个问题 发表人 dennis zane 发表于 2007年7月30日 下午7时57分
  1. 返回顶部

    这个陷阱不具通用性

    2007年7月30日 上午8时14分 发表人 松 刘

    尽管ruby变量可以被赋给任意类型的值,但变量代表的固定意义,使得值的类型多数情况只能一种或少数几种(比如Symbol,String几种). 这个讨论指出了我们可能遇到的陷阱,但没有太大通用性。

  2. 返回顶部

    ruby就是太灵活了

    2007年7月30日 上午8时16分 发表人 立 张

    ruby就是太灵活了

  3. 返回顶部

    并非陷阱

    2007年7月30日 下午7时56分 发表人 li fei

    ||=这个操作符意思是“如果左边的变量值为nil,将它的值赋为右边表达式,否则仅返回左边的变量值。” 解释似乎有误。 我们知道||或运算具有“短路”的性质,也就是只要计算为true就不再计算余下表达式,而直接返回真了。所以||=这个操作符 应该是首先计算 ||=左边的值,为true的话,就直接返回左边的值,为false的话就继续计算,计算 ||=右边的表达式。所以等号右边的表达式是否计算取决于 ||左边的布尔测试。其实a ||= b 应该是 a || a=b 的简写。

  4. 返回顶部

    我不认为这是个问题

    2007年7月30日 下午7时57分 发表人 dennis zane

    你出于某个目的使用一个变量,当你接下来再次使用这个变量肯定是因为相同的目的,可能的混乱根本不会发生。这与ruby需要静态类型的担心是一样的道理。

  5. 返回顶部

    Re: 并非陷阱

    2007年7月31日 下午10时1分 发表人 gpy good

    是的.同意. 该文作者是不是s了点

独家内容

构建的可伸缩性和达到的性能:一个虚拟座谈会

这个由业界主要专家们参加的座谈会探究了在使应用程序具备尽可能好的伸缩性及性能的过程中所面临的挑战和思考过程。

OpenSocial的分析与实现

本视频主要对OpenSocial进行了分析,并对实现的方式进行了介绍。其中包括:OpenSocial的开发经验、Container Provider的技术准备、平台的构成要素、具体的规范、以及对未来的展望。

缓存系统MemCached的Java客户端优化历程

Memcached在大型网站被应用得越来越广泛,但是Java客户端并不多,本文作者基于现有的开源客户端进行了封装优化,并翔实记录了这一过程。

超越SOA:动态业务应用的新企业应用框架(2)

在他们文章的第二部分,作者探讨了动态业务应用的架构并介绍了资源容器的概念。他们示范了如何在JEE之上构建这个架构,以及它如何影响实现生产力。

使用ClickOnce细分发布版本

ClickOnce让WinForms应用程序的部署轻而易举。David Cooksey演示了如何在ASP.NET中编写一个HttpHandler来实现对ClickOnce部署的版本细分。

敏捷教练,从A到Z

敏捷带来了新的领导者角色,“敏捷教练”。它是不是跟“部门经理”或“技术领导”一样,只是换汤不换药呢?教练Pat Kua在这篇启蒙文章中对敏捷教练一职做了概述。

利用Ruby简化你的Java测试(进阶篇)

本文是Productive Java with Ruby系列文章的第二篇,通过上一篇的介绍,我想大家对如何利用Ruby进行单元测试有了一个基本的了解,从这里开始,我将和大家一起讨论一些利用Ruby进行单元测试时的高级话题。

书评:《应用SOA》

《应用SOA》是由四位一流SOA专家合著关于SOA的新书,其主旨是帮助你成功地实施SOA。尤其是,这本书将帮助你把你的SOA项目与企业架构、IT治理、核心数据和BPM项目结合起来。