Ruby 手册 | 09 - 对象的复制与冻结

118 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

一、对象的复制与冻结

在编码过程中有时可能需要一个已有对象的备份,因为已有对象中包含了许多的状态数据,重新创建可能无法满足条件。

变量只是对对象的应用,因此通过 = 赋值符号是无法对对象进行备份的,因为两个变量指向的还是同一个对象

class Female
  attr_accessor :name
end

f = Female.new

f.name = "Penny"
f2 = f
f2.name = "Abby"

puts f.name # Abby
puts f2.name # Abby

但是对于基本数据类型,如字符串,数字在复制时会进行自动赋值操作,不会出现两个变量指向同一个数据。

一般对象的复制,可以使用 Object 类的 clone 方法和 dup 方法。这两个方法功能类似,都可以赋值对象的状态数据,唯一不同的是 clone 方法还能保留与对象相关的方法等内容。

class Female
  attr_accessor :name
end

f1 = Female.new
f1.name = "Penny"

def f1.print_name
  puts "print_name 方法调用了"
end

f2_clone = f1.clone
f3_dup = f1.dup

puts f1.name
puts f2_clone.name
puts f3_dup.name

# 调用对象的方法
f1.print_name
f2_clone.print_name
f3_dup.print_name

执行上述代码,输出结果如下:

Penny
Penny
Penny
print_name 方法调用了
print_name 方法调用了
Traceback (most recent call last):
/ex31.rb:22:in `<main>': undefined method `print_name' for #<Female:0x00007f7abe8367c0 @name="Penny"> (NoMethodError)

使用 dup 方法复制的对象在调用 f1 对象新添加的 print_name 方法时报错了,说明 dup 没有复制到 f1 对象新定义的方法。

在应用中如果不希望自己定义的类被修改,就需要进行冻结操作,冻结对象使用的是 freeze 方法,冻结后在修改该对象会出现 FrozenError 的报错

class Female
  attr_accessor :name
end

f1 = Female.new
f1.name = "Penny"

f1.freeze

def f1.print_name
  puts "f1 对象冻结后再新定义方法"
end

执行上述代码,输出结果如下:

/ex32.rb:10:in `<main>': can't modify frozen object (FrozenError)

Ruby 中一切皆对象,所以也适用于普通的数字和字符串对象,但是要注意如果操作返回了一个新的对象是不适用的。

二、对象序列化

上面提到的 clone 和 dup 都是浅复制,如果对象中还引用了别的对象,只会复制引用,不会复制引用的对象,如果想要实现深度复制,就需要使用到对象的序列化。

在面向对象中,有时候需要将整个对象及其状态报错起来,进行持久化存储,在需要时又可以还原成对象的状态,这个过程就是对象的序列化和反序列化过程。

Ruby 对对象的序列化提供了基本支持,内置的 Marshal 模块可以非常方便的记性对象的序列化和反序列化操作。

class Female
  attr_accessor :name
end

f1 = Female.new
f1.name = "Penny"

puts "=====序列化====="

# 序列化
dump_val = Marshal.dump(f1)
puts dump_val.class

puts "=====反序列化====="

# 反序列化
load_obj = Marshal.load(dump_val)
puts load_obj.class

执行上述代码,输出结果如下:

=====序列化=====
String
=====反序列化=====
Female

对于嵌套比较深的对象可以使用 Marshal 模块来记性序列化操作,可以对对象进行深度复制

对象的序列化和反序列化不仅限于 Marshal 模块,Marshal 模块式 Ruby 的内置模块,处理速度块,其他更常用的还有 YAML 方式进行序列化和反序列化。