You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl使用Hash::Merge合并blessed哈希时丢失键问题求助

问题原因

你遇到的问题是两个点共同导致的:

  1. Hash::Merge 默认不会递归处理被bless过的哈希引用,会直接将其判定为OBJECT类型、当做不可拆分的标量处理,合并时只会保留优先级高的那一个对象的完整内容,不会深入内部合并哈希键值。
  2. 你使用了LEFT_PRECEDENT(左方优先)策略,调用merge时第一个参数(左参数)是$hash2,所以合并时只会保留$hash2的所有内容,$hash1的内容被完全丢弃,自然就没有helper_1键。

修复方案

你可以选择两种方案解决问题,更推荐第二种更简洁的方案:

方案1:自定义Hash::Merge规则兼容blessed哈希

修改Hash::Merge的行为配置,增加对blessed哈希的合并支持,同时调整参数顺序满足你的合并预期(保留$hash1独有的helper_1,用$hash2的helper_2配置覆盖$hash1的原有配置):

#!usr/bin/perl
use strict;
use warnings;
use Hash::Merge;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;

my $hash1 = bless( {
                 'CalcPorts' => {
                                  'helper_1' => {
                                                  'Scope' => [
                                                               ''
                                                             ],
  
                                                },
                                  'helper_2' => {
                                                  'Scope' => [
                                                               ''
                                                             ],
 
                                                },
                                },
 
               }, 'IB' );
my $hash2 = bless( {
                 'CalcPorts' => {
                                  'helper_2' => {
                                                  'Scope' => [
                                                               'd'
                                                             ],
 
                                                },
                                },
 
               }, 'IB' );

my $merger = Hash::Merge->new();
# 自定义支持blessed哈希合并的左优先规则
$merger->add_behavior_spec(
    {
        'SCALAR' => {
            'SCALAR' => sub { $_[0] },
            'ARRAY'  => sub { $_[0] },
            'HASH'   => sub { $_[0] },
        },
        'ARRAY' => {
            'SCALAR' => sub { [ @{$_[0]}, $_[1] ] },
            'ARRAY'  => sub { [ @{$_[0]}, @{$_[1]} ] },
            'HASH'   => sub { $_[0] },
        },
        'HASH' => {
            'SCALAR' => sub { $_[0] },
            'ARRAY'  => sub { $_[0] },
            'HASH'   => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
        },
        'OBJECT' => {
            'OBJECT' => sub {
                # 仅处理同类型的blessed哈希
                if (ref $_[0] eq ref $_[1] && ref $_[0] ne 'ARRAY' && ref $_[0] ne 'SCALAR') {
                    return bless(Hash::Merge::_merge_hashes($_[0], $_[1]), ref $_[0]);
                }
                return $_[0];
            },
            'SCALAR' => sub { $_[0] },
            'ARRAY'  => sub { $_[0] },
            'HASH'   => sub { $_[0] },
        }
    },
    'LEFT_PRECEDENT_BLESSED'
);
# 把$hash2放左位(优先),$hash1放右位
my $hash3 = $merger->merge($hash2, $hash1);

print Dumper($hash3);

方案2:先解bless合并再重新bless(更推荐)

不需要修改Hash::Merge的全局规则,先把两个blessed哈希解引用为普通匿名哈希,合并完成后再重新bless回对应类即可:

#!usr/bin/perl
use strict;
use warnings;
use Hash::Merge;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;

my $hash1 = bless( {
                 'CalcPorts' => {
                                  'helper_1' => {
                                                  'Scope' => [
                                                               ''
                                                             ],
  
                                                },
                                  'helper_2' => {
                                                  'Scope' => [
                                                               ''
                                                             ],
 
                                                },
                                },
 
               }, 'IB' );
my $hash2 = bless( {
                 'CalcPorts' => {
                                  'helper_2' => {
                                                  'Scope' => [
                                                               'd'
                                                             ],
 
                                                },
                                },
 
               }, 'IB' );

my $merger = Hash::Merge->new('LEFT_PRECEDENT');    
# 解引用为普通哈希后合并,再重新bless
my $hash3 = bless(
    $merger->merge(+{%$hash2}, +{%$hash1}),
    'IB'
);

print Dumper($hash3);

运行后输出会符合你的预期,同时保留helper_1和覆盖后的helper_2配置。


内容的提问来源于stack exchange,提问作者urie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 15:24:03