2016-12-29 20 views
3

用Perl 5.24在OS X测试限制哈希更新不是原子仅与`lock_keys`不`lock_hash`

我试图找出原因试图更新受限散列清除哈希表(违反原子)只有当散列的受到限制时。如果lock_hash已应用于散列,则非法修改将完全回滚。

Hash::Util的文档部分声明。

CAVEATS

注意,受限制的操作的捕获不 原子:例如

的eval {%散列=(illegal_key => 1)}

离开%散列空的而不是其原始内容。

我本来想看到像更新单个非法钥匙单独的操作是否是原子和Perl中是否会5.24发射在这种情况下发出警告,但是当我第一次尝试我无法重现行为。

#!/usr/bin/env perl 
use strict; 
use warnings FATAL => 'all'; 
use Hash::Util qw[lock_hash lock_keys]; 
use Data::Dumper; 

my %hash = (a => 1, b => 2); 
lock_hash(%hash); 

eval { %hash = (illegal_key => 1) }; 

print Dumper \%hash; 

这将打印

$VAR1 = { 
      'a' => 1, 
      'b' => 2 
     }; 

使用,lock_keys,但是,确实重现行为

#!/usr/bin/env perl 
use strict; 
use warnings FATAL => 'all'; 
use Hash::Util qw[lock_hash lock_keys]; 
use Data::Dumper; 

my %hash = (a => 1, b => 2); 
lock_keys(%hash); 

eval { %hash = (illegal_key => 1) }; 

print Dumper \%hash; 

打印一个空hashref,如文档预言

$VAR1 = {}; 

根据散列限制的方式,为什么行为有所不同?

+0

您的声音听起来像是您确定它与Perl版本相关。该行为来自模块Hash :: Util。首先阅读它的代码。这可能与Perl的内部相关,但我怀疑5.24中的某些内容在这方面有所改变。 – simbabque

+0

@simbabque我不确定它与Perl版本有关,但我没有在其他Perl版本或其他平台上测试代码片段。我不确定传达这些信息的正确方法。 –

+1

你刚刚做到了。 :-)第二次你说5.24暗示你确定。我会稍微测试一下不同的版本,现在我正在打电话。看看http://perlbrew.pl安装多个不同的Perls,如果你想尝试自己。 – simbabque

回答

1

我已经尝试了两个不同版本的Perl 5.10.1和5.18.2,其行为与您的行为相同,并且在使用旧版本的Perl时可能会存在一些限制。

lock_hash和lock_key之间略有不同。

当你调用lock_hash它:

lock_keys(%$hash); 

foreach my $key (keys %$hash) { 
    lock_value(%$hash, $key); 
} 

所以它锁定你的哈希键和值,而lock_keys:

Internals::hv_clear_placeholders %$hash; 
if(@keys) { 
    my %keys = map { ($_ => 1) } @keys; 
    my %original_keys = map { ($_ => 1) } keys %$hash; 
    foreach my $k (keys %original_keys) { 
     die sprintf "Hash has key '$k' which is not in the new key ". 
        "set at %s line %d\n", (caller)[1,2] 
      unless $keys{$k}; 
    } 

    foreach my $k (@keys) { 
     $hash->{$k} = undef unless exists $hash->{$k}; 
    } 
    Internals::SvREADONLY %$hash, 1; 

    foreach my $k (@keys) { 
     delete $hash->{$k} unless $original_keys{$k}; 
    } 
} 
else { 
    Internals::SvREADONLY %$hash, 1; 
} 

我假定这是一个错误,因为你锁定密钥而不是散列,然后在尝试修改时返回一个空的散列。

但是有些人已经经历过类似像你这样的东西在这个问题:

Should I use Internals::SvREADONLY for creating readonly variables in Perl?

有做你想要什么样的使用TIE或只读例如其他方式。

另外一个内部发生在这里,如果你想看看一条文档编制的:

Internals Documentation

不幸的是这种做法是不鼓励:

SvREADONLY(事,[,$值] )

设置或获取变量是否只读。准确地说,readonly标志的含义取决于受影响的变量的类型和perl的版本。

我们强烈建议您不要直接使用此功能。它被各种核心模块使用,如Hash :: Util和常量编译指令来实现更高层次的行为,而这些行为应该用来代替。

请参阅每个内部变量类型的readonly标志的确切含义的核心实现。