Perl中修改原哈希导致已存入数组的哈希内容意外变更如何解决
问题根因
你代码中存入数组的是\%h,也就是原哈希%h的引用(内存地址),@a1、@a2中存储的都是指向同一个哈希的指针,只要原哈希被修改,所有引用它的位置读取到的都是修改后的值,才会出现你遇到的同步变更问题。
修复方案
方案1:存入数组时构造匿名哈希拷贝
每次往数组push数据时,不要直接传递原哈希的引用,而是对当前哈希做浅拷贝,生成新的匿名哈希引用后再存入,这样后续原哈希的变更就不会影响已经存入数组的内容:
#!/usr/bin/env perl use strict; use warnings FATAL => 'all'; use autodie ':default'; use DDP; my (@a1, @a2); my %h = ('a' => 1); # 对当前%h做浅拷贝,生成新的匿名哈希存入@a1 push @a1, { %h }; $h{b} = 2; # 拷贝当前%h的最新状态存入@a2 push @a2, { %h }; p @a1; p @a2;
运行后输出符合预期:
[ [0] { a 1 } ] [ [0] { a 1, b 2 } ]
方案2:变更哈希状态时重新声明新变量
如果哈希的状态变更节点非常明确,也可以不用复用同一个哈希变量,每次需要新状态时直接声明新的哈希,从根源上避免引用共享:
#!/usr/bin/env perl use strict; use warnings FATAL => 'all'; use autodie ':default'; use DDP; my (@a1, @a2); my %h1 = ('a' => 1); push @a1, \%h1; # 声明新哈希存储新增键值,不修改原有哈希 my %h2 = (%h1, 'b' => 2); push @a2, \%h2; p @a1; p @a2;
该方案性能略优于多次哈希拷贝,适合结构简单、状态拆分明确的场景。
特殊场景说明
如果你需要存储的是多层嵌套的复杂哈希结构,{ %h }的浅拷贝只能复制第一层键值,内层嵌套的引用还是会共享,此时需要做深拷贝,可使用Storable模块的dclone函数实现:
# 先引入深拷贝工具 use Storable qw(dclone); # 存入时调用dclone对哈希做完整深拷贝 push @a1, dclone(\%h);
内容的提问来源于stack exchange,提问作者con
相关产品推荐
相关产品推荐

