Ruby用变量初始化哈希为何保留引用?如何优雅实现initialState
问题背景
习惯React中initialState的独立初始化逻辑,在Ruby中直接复用哈希对象做初始化赋值时,会出现所有引用位置同步更新的问题。
该现象的成因和你的判断一致:Ruby中哈希、数组这类可变对象赋值时传递的是对象内存引用,而非值副本,当多个键指向同一个内存地址的哈希对象时,修改任意一个引用指向的内容,都会同步改动所有关联位置的取值。
问题复现代码如下:
iniatializing_hash = {likes_count: 0, comments_count: 0} hash_that_uses_initializer = {first: iniatializing_hash, second: iniatializing_hash} # 更新first对应的哈希 hash_that_uses_initializer[:first][:likes_count] += 1 hash_that_uses_initializer[:first][:comments_count] += 1 puts "first: #{hash_that_uses_initializer[:first].inspect} and second: #{hash_that_uses_initializer[:second].inspect}" # 输出:first: {:likes_count=>1, :comments_count=>1} and second: {:likes_count=>1, :comments_count=>1}
实现类initialState独立初始化的方案
以下几种方式都可以实现每个初始化位置生成独立哈希副本、修改互不影响的效果:
- 浅拷贝生成单层哈希副本
对于没有嵌套结构的单层哈希,直接在赋值时对初始化模板调用dup方法生成浅副本即可,不需要提前共享同一个哈希对象:# 定义初始化模板 initial_state = {likes_count: 0, comments_count: 0} independent_hash = { first: initial_state.dup, second: initial_state.dup } independent_hash[:first][:likes_count] += 1 independent_hash[:first][:comments_count] += 1 puts "first: #{independent_hash[:first].inspect} and second: #{independent_hash[:second].inspect}" # 输出:first: {:likes_count=>1, :comments_count=>1} and second: {:likes_count=>0, :comments_count=>0} - 用Hash默认块自动生成独立初始值
如果需要动态添加大量同初始结构的哈希项,可以使用Hash的块初始化语法,每次访问不存在的键时,自动生成独立的初始状态副本,不存在引用共享问题:# 初始化哈希,访问不存在的key时自动赋值独立的初始状态 state_store = Hash.new do |hash, key| hash[key] = {likes_count: 0, comments_count: 0} end # 直接操作不存在的键即可完成独立初始化 state_store[:first][:likes_count] += 1 state_store[:first][:comments_count] += 1 puts "first: #{state_store[:first].inspect} and second: #{state_store[:second].inspect}" # 输出:first: {:likes_count=>1, :comments_count=>1} and second: {:likes_count=>0, :comments_count=>0} - 深拷贝处理嵌套结构
如果初始化的哈希包含嵌套的可变对象(比如哈希中嵌套数组、其他哈希),dup的浅拷贝只会复制外层对象,嵌套层依然会共享引用,此时可以用Marshal做序列化深拷贝,生成完全独立的对象:nested_initial = {counts: {likes: 0, comments: 0}, tags: []} nested_state_hash = { first: Marshal.load(Marshal.dump(nested_initial)), second: Marshal.load(Marshal.dump(nested_initial)) } nested_state_hash[:first][:counts][:likes] += 1 nested_state_hash[:first][:tags] << "new_tag" # second对应的哈希不会被上述修改影响
内容的提问来源于stack exchange,提问作者madav
相关产品推荐
相关产品推荐

