把 '1' 存储在 Set-Hash 中被认为是有害的
我知道使用被认为有害是有害的,但这很糟糕,几乎和不受限制的 goto
使用一样糟糕。
好吧,我在几个评论中已经强调了这一点,但我认为我需要一个完整的回应来证明这个问题。
假设我们有一个守护进程,为销售小部件的商店提供后端库存控制。
my @items = qw(
widget
thingy
whozit
whatsit
);
my @items_in_stock = qw(
widget
thingy
);
my %in_stock;
my @in_stock(@items_in_stock) = (1) x @items_in_stock;
sub Process_Request {
my $request = shift;
if( $request eq REORDER ) {
Reorder_Items(\@items, \%in_stock);
}
else {
Error_Response( ILLEGAL_REQUEST );
}
}
sub Reorder_Items{
my $items = shift;
my $in_stock = shift;
for my $item ( @$items ) {
Reorder_Item( $item )
if not exists $in_stock->{$item};
}
}
这个工具很棒,可以自动保持货物库存,非常好用。现在老板想要自动生成有库存的商品目录,所以我们修改 Process_Request()
并添加生成目录的功能。
sub Process_Request {
my $request = shift;
if( $request eq REORDER ) {
Reorder_Items(\@items, \%in_stock);
}
if( $request eq CATALOG ) {
Build_Catalog(\@items, \%in_stock);
}
else {
Error_Response( ILLEGAL_REQUEST );
}
}
sub Build_Catalog {
my $items = shift;
my $in_stock = shift;
my $catalog_response = '';
foreach my $item ( @$items ) {
$catalog_response .= Catalog_Item($item)
if $in_stock->{$item};
}
return $catalog_response;
}
在测试中,Build_Catalog()
运行良好。太好了,我们可以发布应用程序了。
糟糕。由于某种原因,没有任何东西被订购,公司的所有库存都已经耗尽。
Build_Catalog()
例程向%in_stock
添加键,因此Reorder_Items()
现在将所有物品视为有库存,并且永远不会下订单。
使用Hash::Util的lock_hash
可以帮助防止意外哈希修改。如果在调用Build_Catalog()
之前锁定了%in_stock
,我们将收到致命错误,并且永远不会发布带有错误的应用程序。
总之,最好测试键的存在而不是集合哈希值的真实性。如果您使用存在作为标志,请不要将值设置为“1”,因为这将掩盖错误并使其更难以跟踪。使用lock_hash
可以帮助捕捉这些问题。
如果你必须检查值的真实性,在每种情况下都这样做。