Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 锁定哈希键以防止删除_Perl - Fatal编程技术网

Perl 锁定哈希键以防止删除

Perl 锁定哈希键以防止删除,perl,Perl,PerlV5.8.0引入了受限哈希和Hash::Util核心模块作为该功能的接口。其中提到的一个功能是“锁定单个密钥以使其无法删除的功能”。然而,模块中似乎没有提供此功能:无论是lock_keys()还是lock_values()都不会阻止删除密钥,而lock_hash()都不会阻止删除和修改所有密钥 那么,如何锁定单个密钥以使其无法删除?该模块仅提供一种方法,使受限哈希的元素既不可变又不可删除 为了达到你想要的效果,你需要魔法,比如绑定哈希 package My::Protected::Has

PerlV5.8.0引入了受限哈希和
Hash::Util
核心模块作为该功能的接口。其中提到的一个功能是“锁定单个密钥以使其无法删除的功能”。然而,模块中似乎没有提供此功能:无论是
lock_keys()
还是
lock_values()
都不会阻止删除密钥,而
lock_hash()
都不会阻止删除和修改所有密钥


那么,如何锁定单个密钥以使其无法删除?

该模块仅提供一种方法,使受限哈希的元素既不可变又不可删除

为了达到你想要的效果,你需要魔法,比如绑定哈希

package My::Protected::Hash;

use strict;
use warnings;

use Carp      qw( );
use Tie::Hash qw( );

our @ISA = 'Tie::ExtraHash';

# Usage: tie my %hash, My::Protected::Hash::, LIST
sub TIEHASH  {
   my $class = shift;
   my $self = bless([{}, {}]);
   $self->[1]{$_} = 1 for @_;
   return $self;
}

sub DELETE {
   my ($self, $key) = @_;
   Carp::croak("Can't delete key \"$key\"") if $self->[1]{$key};
   return delete($self->[0]{$key});
}

# Usage: tied(%hash)->lock_key(LIST)
sub lock_key {
   my $self = shift;
   $self->[1]{$_} = 1 for @_;
}

# Usage: tied(%hash)->unlock_key(LIST)
sub unlock_key {
   my $self = shift;
   delete @{ $self->[1] }{@_};
}

1;
例如:

use strict;
use warnings;
use feature qw( say );

use FindBin qw( $RealBin );
use lib $RealBin;

use My::Protected::Hash qw( );

tie my %h, My::Protected::Hash::, "b", "c";
tied(%h)->unlock_key("b");
tied(%h)->lock_key("d");
for my $key (qw( a b c )) {
   if (eval { delete $h{$key}; 1 }) {
      say "Deleted key \"$key\"";
   } else {
      print $@;
   }
}
输出:

已删除键“a”
已删除键“b”
无法删除a.pl第16行的键“c”。
无法删除a.pl第16行的键“d”。

ikegami的答案当然是一个很好的例子,说明了如何在不使用受限哈希的情况下实现既定目标。我将根据我在研究中发现的信息回答我自己的问题,并从对原始问题的评论中获得帮助,重点关注受限散列可以做什么和不能做什么。这里我的技术评估是基于实验和使用
Devel::Peek
来查看底层数据结构的样子

首先,
Hash::Util
文档似乎有误导性。虽然从技术上讲,人们可以锁定单个密钥,以便它们不能被删除,但唯一的方法是也锁定它们以防修改。如果您希望键是可变的但不可删除的,那么没有允许它的设置。您可以使用基于tie的解决方案(如ikegami),也可以使用sub/方法解决该问题,该方法临时禁用只读限制,更新值,然后再次使其为只读

受限哈希通过两种技巧工作:只读标志,以及Perl将其视为“密钥不存在”的密钥的特殊占位符值(空引用)。只读标志可以应用于哈希或哈希中的值。
lock\u keys()
函数操作散列上的只读标志;
lock\u value()
函数对单个值进行操作。
lock\u hash()
函数只是同时执行这两个操作,会影响哈希和其中的所有值,因此我们只需要了解前两个函数就可以了解该过程

散列上的只读标志本身防止在散列中添加或删除任何键。乍一看,这似乎是我想要的,但有一个皱纹。使用受限哈希的想法是限制可能出现在哈希中的一组键,而不强制这些键出现。因此,您仍然可以在只读哈希中删除键,但是可以通过将当前值替换为我前面提到的一个特殊的占位符值来模拟删除。从运行代码的角度来看,键已经不存在了,但实际上它仍然存在于底层数据结构中,如果您使用
Devel::Peek
中的Dump函数,它是可见的

lock_keys()
函数有两个变体,分别处理已存在的密钥和未存在的密钥。如果只调用
锁定键(%x)
,只需将READONLY标志应用于
%x
。如果调用
lock_keys(%x,@keys)
,则该过程更复杂:首先,如果
%x
包含
@keys
中不存在的任何键,则会引发异常;然后,
%x
将填充
@keys
中尚未出现在
%x
中的所有键;然后应用只读标志;然后再次删除添加到
%x
的键,使它们与“不存在”占位符关联。
lock\u keys\u plus()。如果基本
lock\u keys(%x)
函数是唯一可用的函数,那么您必须使用所有允许的密钥初始化哈希,锁定它,然后删除您当时不想要的条目

lock\u value()
函数更简单,因为它只是将只读标志应用于哈希中的选定值。如果在哈希本身不是只读的情况下执行此操作,则会收到一条警告,说明它是一个无用的操作。这并不是完全正确的:值上的READONLY标志确实使值成为只读的,它只是不能防止从哈希中删除值并替换为非只读的新值。这就把我们带到了下一点:值上的READONLY标志保护它不被替换为特殊的占位符,这使它看起来像元素已被删除,当散列本身处于只读模式时使用。因此,当散列本身是只读的时,不能删除散列中的只读值

奇怪的是,READONLY标志不能防止的一件事是使用
hv\u store()
函数替换值。虽然这无法将密钥添加到已锁定的哈希中,但它可以将锁定的值完全替换为未锁定的值。我想如果你在这么深的地方进行黑客攻击,你就应该提供自己的保护,防止修改锁定的值,如果这是你想要的。请注意,这还提供了一种使普通标量成为只读的巧妙方法:使用
hv_store()
将其别名为任意散列,然后锁定散列

这在很大程度上取决于实现,并且
Hash::Util
文档偶尔会发出关于实现可能如何更改的威胁性噪音,但从v5.8.0开始就是这样。到v5.30.0,据我所知。新功能出现在最新版本中,但我认为我的描述贯穿了整个历史。如果您知道与我所说的有任何重要偏差,请添加评论。

您可以使用绑定哈希