将两个哈希值与混合类型进行比较

nur*_*urp 7 perl hash

如果第二个哈希中的键值对相同​​,我想比较哈希值.我不想使用smartmatch,因为它会发出警告.

将两个哈希值与整数,字符串以及可能还有数组进行比较的最佳方法是什么?

use warnings;
use diagnostics;

my $hash1={"key_str"=>"a string", "key_int"=>4};
my $hash2={"key_str"=>"b string", "key_int"=>2};

foreach my $key ( keys(%$hash1) ) {
    if ($hash1->{$key} != $hash2->{$key}) {
        print($key);
    }
}
Run Code Online (Sandbox Code Playgroud)

预期的输出是:

Argument "b string" isn't numeric in numeric ne (!=) at hash_compare.pl line 8 (#1)
    (W numeric) The indicated string was fed as an argument to an operator
    that expected a numeric value instead.  If you're fortunate the message
    will identify which operator was so unfortunate.

Argument "a string" isn't numeric in numeric ne (!=) at hash_compare.pl line 8 (#1)
Run Code Online (Sandbox Code Playgroud)

sim*_*que 8

首先,Perl没有类型.它不区分字符串和数字(​​在外面).

此外,它在这个级别上的数字和字符串之间没有区别.如果你检查更大或更小的数字上下文字符串上下文很重要.考虑一下:

my $foo = 200;
my $bar = 99;
print $foo > $bar ? $foo : $bar;
Run Code Online (Sandbox Code Playgroud)

显然它会打印200,因为200在数值上大于99.

my $foo = 200;
my $bar = 99;
print $foo gt $bar ? $foo : $bar;
Run Code Online (Sandbox Code Playgroud)

但这将打印99,因为9字母数字(如字符串)大于2.它比较了字符的代码点数.

但如果您只想检查不平等,那么ne运营商就可以了.即使你不确定输入中是否还有数字以外的东西.

foreach my $key ( keys(%$hash1) ) {
    if ($hash1->{$key} ne $hash2->{$key}) {
        print($key);
    }
}
Run Code Online (Sandbox Code Playgroud)

eq(和ne)足够聪明,看看一个数字最初是一个字符串还是一个没有引号的数字,因为它们的内部表示不同.

警告,技术细节未来.

标量值保存在_SV_s中.这些术语可以包含不同的东西.对于称为IV的简单整数,有一种特殊的内部类型,还有一种称为PV的字符串.当你在字符串中使用数字时,Perl会根据需要在这两者之间进行内部转换,反之亦然.

您可以DumpDevel :: Peek获取有关数据内部表示的一些调试信息.

use Devel::Peek;

Dump("01");
Dump(01);
Run Code Online (Sandbox Code Playgroud)

这将输出:

SV = PV(0x19560d0) at 0x19327d0
  REFCNT = 1
  FLAGS = (POK,READONLY,IsCOW,pPOK)
  PV = 0x1c94fd0 "01"\0
  CUR = 2
  LEN = 10
  COW_REFCNT = 0
SV = IV(0x19739b0) at 0x19739c0
  REFCNT = 1
  FLAGS = (IOK,READONLY,pIOK)
  IV = 1
Run Code Online (Sandbox Code Playgroud)

如您所见,第一个是字符串,第二个是数字.但是,如果我们这样做

print "01" eq 01;
Run Code Online (Sandbox Code Playgroud)

没有输出,因为它01是一个整数,将被转换"1"为比较.由于0"01"不等于1说,没有东西打印出来.


如果数据结构的值更复杂,则需要遍历结构.每种类型的元素都需要有自己的处理.可能有数组引用,哈希引用,标量引用,标量,glob引用,dualvars等.可能有您想特别对待的对象.

我建议看看Test :: Deep如何实现这一点.如果您决定在生产代码中使用它(而不是单元测试),则可以使用Test :: Deep :: NoTest.

  • @Borodin在这种情况下,他们必须坚持我的第二点并自己构建很多东西.来自Scalar :: Util的`is_dual`来识别_dualvar_s.有趣的是,Test :: Deep不会这样做.`cmp_deeply(dualvar(1337,'bar'),dualvar(1337,'foo'))`会失败,因为`foo`不是`bar`.如果数字不同但字符串相同,它将通过.它从不关注数字部分.可能是因为Test :: Deep也在非refs上使用`eq`. (2认同)