我希望这篇帖子能作为大家 Ruby 开发注意事项的一个总结,欢迎大家跟帖,说说我们自己在 Ruby 开发中遇到的坑
最近在看Liquid源码时看到一句
def render(*args)
return ''.freeze if @root.nil?
...
end
所以我就看了看freeze
方法的定义。
它是 Object 的实例方法,所以基本上所有的 Ruby 对象都继承了 Object 的 freeze 方法。
为了进一步搞明白作者写 ‘’.freeze
的意图,我就在命令行试了试 freeze
# ruby 2.2.3
> a = ''
=> ""
> a.freeze
=> ""
> a << 'b'
RuntimeError: can't modify frozen String
from (irb):3
from /home/i/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
> a += 'c'
=> "c"
> a
=> "c"
> a.freeze
=> "c"
> a << 'b'
RuntimeError: can't modify frozen String
from (irb):7
from /home/i/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
> a += 'd'
=> "cd"
freeze
只是禁止了<<
操作,但是对于 =、+
却可以,而且一旦使用了运算符,或者说调用了+、=
方法,变量又从frozen
状态回到了正常状态,
> a.freeze
=> "cd"
> a << 'e'
RuntimeError: can't modify frozen String
from (irb):12
from /home/i/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
> a.frozen?
=> true
> a += 'e'
=> "cde"
> a.frozen?
=> false
官方文档是这样说的
There is no way to unfreeze a frozen object. See also Object#frozen?.
但是我们做到了
对于 Fixnum, Bignum, Float, Symbol 来说永远是 Frozen 状态。
Objects of the following classes are always frozen: Fixnum, Bignum, Float, Symbol.
我又试了下数组
> a = [1]
=> [1]
> a.freeze
=> [1]
> a << 2
RuntimeError: can't modify frozen Array
from (irb):44
from /home/i/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
> a += [2]
=> [1, 2]
> a
=> [1, 2]
> a.frozen?
=> false
> a.freeze
=> [1, 2]
> a -= [2]
=> [1]
> a.frozen?
=> false
所以,对于数组来说,也并没有真正的做到 freeze。
对于frozen
的对象来说,只是禁止了<<
操作符而已。不知道是 bug 还是故意设计的。
虽然,这个方法用的相对比较少,但是记录在这里,希望起到抛砖引玉的作用。
----------------------------------------------------2015.10.25---------------------------------------- 补充: 昨晚睡觉的时候,突然想起来应该看看 ruby 源码
今天起来一看,果然+
操作符返回的是一个新的字符串,而<<
是concat
的别名,返回对象本身。
所以freeze
是对对象本身的操作。