Ruby 的一个陷阱

今天是 2010-01-25. 我在 irb 中测试 Date 类的 today 方法:

>> (Date.today -1 ).to_s
=> "2010-01-25"
>> (Date.today - 1).to_s
=> "2010-01-24"
>> (Date.today-1).to_s
=> "2010-01-24"

结果多少让人有点吃惊。第一次我输入太快发生了错误,减号和 1 之间的空格被我敲到 1 后面去了,但是两次结果竟然不一样!

不过我很快回过神来了,第一次输入,Ruby 把 -1 解释成为 today 方法的参数了。因为 Ruby 的方法调用可以不加括号,虽然不鼓励所有的函数调用都这么干,但是去掉一对空的括号是被鼓励的(ref)。例如 puts,我就没见过有人调用它会加括号。

再看第三个输入,那些对空格很吝啬的人也不会遇到这样的问题,除非他不小心在减号前打了一个空格。运算符和操作数之间的空格竟然影响了程序的解释结果,这让人很纠结。为了保险起见,我还是给这个方法调用加上了一对空的括号。

假如 Ruby 像其它语言一样要求方法调用必须加括号,这个问题就不会存在。对于解释型语言来说,语法的灵活很可能导致解释效率的降低。不过这么多人喜欢 Ruby,也有一部分原因是它跟其它语言很不一样。

我忽然想到,如果大学里面有 Ruby 课程(千万不要是必修,把大学变成培训班),肯定会有某些老师把上面的这个小把戏作为考试题,看着学生们出错得意地笑。就如同考察逻辑运算符的优先级一样无聊,其实只要记住括号的优先级最高就行了。

另外,假如 Ruby 像其它语言一样要求方法调用必须加括号,有的 callback 实现就会更简单。把方法作为参数传递的时候,像 Python 一样直接写方法名不就可以了吗?不行,这是一个方法,方法调用不必要加括号,Ruby 解释器发现了方法名就会尝试执行它。所以得写成 “method(:my_callback)”,才能传入一个 Method object. 又因为这是一个 Method object,所以调用它的时候也不能像 Python 一样简单地写 “callback(…)” 了,需要写成 “callback.call(…)”.

看来“可省略的括号”使得这种思路的实现复杂化了,不过似乎 block 也是无所不能……

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.