假设我有一个大哈希,我想迭代它的内容.标准的习语是这样的:
while(($key, $value) = each(%{$hash_ref})){
///do something
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我理解我的perl,这实际上是做了两件事.首先是
%{$hash_ref}
Run Code Online (Sandbox Code Playgroud)
正在将ref翻译成列表上下文.因此返回类似的东西
(key1, value1, key2, value2, key3, value3 etc)
Run Code Online (Sandbox Code Playgroud)
它将存储在我的堆栈内存中.然后每个方法都会运行,在内存中使用前两个值(key1和value1)并将它们返回到我的while循环进行处理.
如果我对此的理解是正确的,这意味着我已经有效地将我的整个哈希复制到我的堆栈内存中,只是迭代新的副本,这对于大型哈希来说可能是昂贵的,因为迭代数组两次的费用,但是如果两个哈希值都不能同时保存在内存中,也会导致潜在的缓存命中.看起来效率很低.我想知道这是不是真的发生了,或者我是否误解了实际行为,或者编译器是否为我的效率低下了?
跟进问题,假设我对标准行为是正确的.
是否有一种语法可以避免通过在原始哈希中迭代它来复制哈希值?如果不是哈希那么更简单的数组呢?
这是否意味着在上面的示例中,如果我修改了循环中的hash_ref内容,我可能会在哈希副本和实际哈希值之间得到不一致的值; 导致$ value具有不同的值,然后$ hash_ref - >($ key)?
不,您引用的语法不会创建副本.
这个表达式:
%{$hash_ref}
Run Code Online (Sandbox Code Playgroud)
完全等同于:
%$hash_ref
Run Code Online (Sandbox Code Playgroud)
并且假设$hash_ref
标量变量确实包含对散列的引用,那么%
在前面添加简单地"解除引用"引用 - 即它解析为表示底层散列($hash_ref
指向的东西)的值.
如果查看每个函数的文档,您会看到它希望将哈希作为参数.把%
你的东西放在hashref上是如何提供哈希的.
如果您编写了自己的子例程并将哈希传递给它,就像这样:
my_sub(%$hash_ref);
Run Code Online (Sandbox Code Playgroud)
然后在某种程度上你可以说哈希被"复制"了,因为在子程序中,特殊@_
数组将包含来自哈希的所有键/值对的列表.但即使在这种情况下,@ _的元素实际上是键和值的别名.如果您执行以下操作,您实际上只能获得一份副本:my @args = @_
.
Perl的内置each
函数使用原型'+'声明,它有效地将哈希(或数组)参数强制转换为对底层数据结构的引用.
另外,从版本5.14开始,该each
函数也可以引用哈希.所以代替:
($key, $value) = each(%{$hash_ref})
Run Code Online (Sandbox Code Playgroud)
你可以简单地说:
($key, $value) = each($hash_ref)
Run Code Online (Sandbox Code Playgroud)
不会创建任何副本each
(尽管您确实将返回值复制到赋值中$key
并$value
通过赋值)。哈希本身被传递到each
.
each
有点特别。它支持以下语法:
each HASH
each ARRAY
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它不接受任意表达式。(那就是each EXPR
或each LIST
)。这样做的原因是允许each(%foo)
将哈希%foo
本身传递给each
而不是在列表上下文中对其进行评估。each
可以做到这一点,因为它是一个运算符,并且运算符可以有自己的解析规则。但是,您可以对原型执行类似的操作\%
。
use Data::Dumper;
sub f { print(Dumper(@_)); }
sub g(\%) { print(Dumper(@_)); } # Similar to each
my %h = (a=>1, b=>2);
f(%h); # Evaluates %h in list context.
print("\n");
g(%h); # Passes a reference to %h.
Run Code Online (Sandbox Code Playgroud)
输出:
$VAR1 = 'a'; # 4 args, the keys and values of the hash
$VAR2 = 1;
$VAR3 = 'b';
$VAR4 = 2;
$VAR1 = { # 1 arg, a reference to the hash
'a' => 1,
'b' => 2
};
Run Code Online (Sandbox Code Playgroud)
%{$h_ref}
与 相同%h
,因此以上所有内容%{$h_ref}
也适用。
请注意,即使散列被展平,也不会被复制。键被“复制”,但值被直接返回。
use Data::Dumper;
my %h = (abc=>"def", ghi=>"jkl");
print(Dumper(\%h));
$_ = uc($_) for %h;
print(Dumper(\%h));
Run Code Online (Sandbox Code Playgroud)
输出:
$VAR1 = {
'abc' => 'def',
'ghi' => 'jkl'
};
$VAR1 = {
'abc' => 'DEF',
'ghi' => 'JKL'
};
Run Code Online (Sandbox Code Playgroud)
您可以在此处阅读有关此内容的更多信息。
归档时间: |
|
查看次数: |
171 次 |
最近记录: |