最近在看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 还是故意设计的。
虽然,这个方法用的相对比较少,但是记录在这里,希望起到抛砖引玉的作用。
今天起来一看,果然+
操作符返回的是一个新的字符串,而<<
是concat
的别名,返回对象本身。 所以freeze
是对对象本身的操作。
a.freeze
冻结了 a
指向的对象,<<
直接修改对象,操作被阻止。+=
将 a
指向新的对象,操作没有被阻止。