深入探索

冻结对象

通过了解所有这些修改对象的方法,你可能会担心对象有被无意中修改掉的风险。实际上,你可以通过“冻结”它(使用 freeze 方法)来专门固定住对象的状态。一旦冻结,就无法修改对象包含的数据,如果尝试这样做,将抛出 TypeError 异常。然而,在冻结对象时要小心,因为一旦冻结,它就不能“解冻”(unfrozen)。

freeze.rb
  1. s = "Hello"
  2. s << " world"
  3. s.freeze
  4. s << " !!!" # Error: "can't modify frozen string (TypeError)"

你可以使用 frozen? 来专门检查对象是否被冻结:

  1. a = [1,2,3]
  2. a.freeze
  3. if !(a.frozen?) then
  4. a << [4,5,6]
  5. end

请注意,虽然无法修改冻结对象的数据,但可以修改定义它的类。假设你有一个类 X,它包含一个方法 addMethod,它可以使用给出的符号名称创建新的方法 m

cant_freeze.rb
  1. def addMethod( m, &block )
  2. self.class.send( :define_method, m , &block )
  3. end

现在,如果你有一个从 M 类创建的对象 ob,那么调用 addMethod 来向 M 类添加一个新方法是完全合法的:

  1. ob.freeze
  2. ob.addMethod( :abc ) { puts("This is the abc method") }

当然,如果你想阻止冻结的对象它的所属类,可以使用 frozen? 方法来测试它的状态:

  1. if not( ob.frozen? ) then
  2. ob.addMethod( :def ) { puts("'def' is not a good name for a method") }
  3. end

你也可以冻结类本身(记住,类也是一个对象):

  1. X.freeze
  2. if not( X.frozen? ) then
  3. ob.addMethod( :def ) { puts("'def' is not a good name for a method") }
  4. end