Perl - Hash::Merge 丢失密钥
Perl - Hash::Merge loses keys
我正在尝试在 Perl 中合并两个 blessed 哈希。
我是运行以下代码:
#!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');
my $hash3 = $merger->merge($hash2, $hash1);
print Dumper($hash3);
输出是这样的:
$VAR1 = bless( {
'CalcPorts' => {
'helper_2' => {
'Scope' => [
'd'
]
}
}
}, 'IB' );
尽管我希望“helper_1”会在那里...
任何想法我做错了什么?
感谢您的帮助:)
Hash::Merge
认为任何 ref
不是 HASH
或 ARRAY
的东西都是标量,并对这些项目应用标量合并规则(参见 those lines 的执行 Hash::Merge
)。合并 2 个标量时,Hash::Merge
要么丢弃其中一个,要么创建一个数组来存储它们。 None 这个选项合并了受祝福的哈希值。
为了克服这个问题,你可以先取消祝福你的哈希(例如使用Data::Structure::Util::unbless
),然后合并它们,然后重新祝福它们:
use Data::Structure::Util qw(unbless);
my $class = ref $hash1;
unbless $hash1;
unbless $hash2;
my $hash3 = bless $merger->merge($hash2, $hash1), $class;
如果你的主哈希中有 blessed 哈希,那么你可以使用 add_behavior_spec
方法定义你自己的 Hash::Merge
行为:对于 SCALAR
-SCALAR
情况,检查两个标量是否都是受祝福的引用,如果是,则取消祝福、合并和重新祝福:
$merger->add_behavior_spec(
{ 'SCALAR' => {
'SCALAR' => sub {
my $self = &Hash::Merge::_get_obj;
my ($left, $right) = @_;
my ($class_left, $class_right) = (ref $left, ref $right);
if ($class_left && $class_left eq $class_right) {
unbless $left;
unbless $right;
return bless $self->merge($left, $right), $class_left;
} else {
return $_[1]; # Or something else
}
},
'ARRAY' => ...,
'HASH' => ...,
},
ARRAY => { ... },
HASH => { ... }
为简洁起见,我将 ...
留给不相关的案例。您可以从 the source of Hash::Merger
(choosing the behavior that you want). Or, maybe easier, you can use get_behavior_spec
and get_behavior
方法中复制粘贴这些内容以更改当前行为的 SCALAR
-SCALAR
情况:
my $behavior = $merger->get_behavior_spec($merger->get_behavior);
my $old_behavior_scalar_scalar = $behavior->{SCALAR}{SCALAR};
$behavior->{SCALAR}{SCALAR} = sub {
my $self = &Hash::Merge::_get_obj;
my ($left, $right) = @_;
my ($class_left, $class_right) = (ref $left, ref $right);
if ($class_left && $class_left eq $class_right) {
unbless $left;
unbless $right;
return bless $self->merge($left, $right), $class_left;
} else {
# Regular scalars, use old behavior
return $old_behavior_scalar_scalar->($left, $right);
}
};
请注意,这不能很好地处理您想要合并 2 个散列到 2 个不同包的情况。你必须为那些实施特殊情况。 (不清楚合并此类哈希的一般规则是什么)
我正在尝试在 Perl 中合并两个 blessed 哈希。
我是运行以下代码:
#!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');
my $hash3 = $merger->merge($hash2, $hash1);
print Dumper($hash3);
输出是这样的:
$VAR1 = bless( {
'CalcPorts' => {
'helper_2' => {
'Scope' => [
'd'
]
}
}
}, 'IB' );
尽管我希望“helper_1”会在那里... 任何想法我做错了什么? 感谢您的帮助:)
Hash::Merge
认为任何 ref
不是 HASH
或 ARRAY
的东西都是标量,并对这些项目应用标量合并规则(参见 those lines 的执行 Hash::Merge
)。合并 2 个标量时,Hash::Merge
要么丢弃其中一个,要么创建一个数组来存储它们。 None 这个选项合并了受祝福的哈希值。
为了克服这个问题,你可以先取消祝福你的哈希(例如使用Data::Structure::Util::unbless
),然后合并它们,然后重新祝福它们:
use Data::Structure::Util qw(unbless);
my $class = ref $hash1;
unbless $hash1;
unbless $hash2;
my $hash3 = bless $merger->merge($hash2, $hash1), $class;
如果你的主哈希中有 blessed 哈希,那么你可以使用 add_behavior_spec
方法定义你自己的 Hash::Merge
行为:对于 SCALAR
-SCALAR
情况,检查两个标量是否都是受祝福的引用,如果是,则取消祝福、合并和重新祝福:
$merger->add_behavior_spec(
{ 'SCALAR' => {
'SCALAR' => sub {
my $self = &Hash::Merge::_get_obj;
my ($left, $right) = @_;
my ($class_left, $class_right) = (ref $left, ref $right);
if ($class_left && $class_left eq $class_right) {
unbless $left;
unbless $right;
return bless $self->merge($left, $right), $class_left;
} else {
return $_[1]; # Or something else
}
},
'ARRAY' => ...,
'HASH' => ...,
},
ARRAY => { ... },
HASH => { ... }
为简洁起见,我将 ...
留给不相关的案例。您可以从 the source of Hash::Merger
(choosing the behavior that you want). Or, maybe easier, you can use get_behavior_spec
and get_behavior
方法中复制粘贴这些内容以更改当前行为的 SCALAR
-SCALAR
情况:
my $behavior = $merger->get_behavior_spec($merger->get_behavior);
my $old_behavior_scalar_scalar = $behavior->{SCALAR}{SCALAR};
$behavior->{SCALAR}{SCALAR} = sub {
my $self = &Hash::Merge::_get_obj;
my ($left, $right) = @_;
my ($class_left, $class_right) = (ref $left, ref $right);
if ($class_left && $class_left eq $class_right) {
unbless $left;
unbless $right;
return bless $self->merge($left, $right), $class_left;
} else {
# Regular scalars, use old behavior
return $old_behavior_scalar_scalar->($left, $right);
}
};
请注意,这不能很好地处理您想要合并 2 个散列到 2 个不同包的情况。你必须为那些实施特殊情况。 (不清楚合并此类哈希的一般规则是什么)