Joh*_*ann 5 perl hash pass-by-reference pass-by-value
我正在使用子程序来制作一些不同的哈希映射.我目前正在通过引用传递hashmap,但是多次执行时会出现这种情况.我应该按值传递哈希值还是传递哈希引用?
use strict;
use warnings;
sub fromFile($){
local $/;
local our %counts =();
my $string = <$_[0]>;
open FILE, $string or die $!;
my $contents = <FILE>;
close FILE or die $!;
my $pa = qr{
( \pL {2} )
(?{
if(exists $counts{lc($^N)}){
$counts{lc($^N)} = $counts{lc($^N)} + 1;
}
else{
$counts{lc($^N)} = '1';
}
})
(*FAIL)
}x;
$contents =~ $pa;
return %counts;
}
sub main(){
my %english_map = &fromFile("english.txt");
#my %german_map = &fromFile("german.txt");
}
main();
Run Code Online (Sandbox Code Playgroud)
当我单独运行不同的txt文件时,我没有遇到任何问题,但两者都有一些冲突.
ike*_*ami 11
三条评论:
传递引用是传递包含引用(一种值)的标量.
编译器通过一个参数作为参考,当它通过该参数不进行复制.
编译器在传递参数副本时按值传递参数.
修改函数的参数(元素@_)将更改调用者中的相应变量.这是复制参数的约定存在的原因之一.
my ($x, $y) = @_; # This copies the args.
Run Code Online (Sandbox Code Playgroud)
当然,复制参数的主要原因是"命名"它们,但它使我们免于通过@_直接使用元素获得的一些令人讨厌的惊喜.
$ perl -E'sub f { my ($x) = @_; "b"=~/(.)/; say $x; } "a"=~/(.)/; f($1)'
a
$ perl -E'sub f { "b"=~/(.)/; say $_[0]; } "a"=~/(.)/; f($1)'
b
Run Code Online (Sandbox Code Playgroud)
唯一可以传递给Perl子的是标量列表.(它也是唯一一个可以归还的东西.)
从@a评估到$a[0], $a[1], ...列表上下文,
foo(@a)
Run Code Online (Sandbox Code Playgroud)
是相同的
foo($a[0], $a[1], ...)
Run Code Online (Sandbox Code Playgroud)
这就是为什么我们创建对我们想要传递给sub并传递引用的数组或哈希的引用.
如果我们不这样做,那么数组或散列将被计算为标量列表,并且必须在子内部重建.这不仅价格昂贵,而且在某些情况下也是不可能的
foo(@a, @b)
Run Code Online (Sandbox Code Playgroud)
因为foo无法知道返回了多少个参数@a以及返回了多少个参数@b.
请注意,可以使用原型将其看作数组或散列作为参数传递,但原型只会导致自动创建对数组/散列的引用,这就是实际传递给sub的内容.
出于几个原因,您应该使用pass-by-reference,但是您显示的代码会按值返回哈希值.
你应该使用my而不是local像内置变量那样使用$/,然后只使用尽可能小的范围.
子程序的原型几乎不是一个好主意.他们做了非常具体的事情,如果你不知道那是什么,你就不应该使用它们.
&fromFile("english.txt")自从大约二十年前的Perl 4以来,使用&符号来调用子程序就像是一样.它以至少两种不同的方式影响传递给子程序的参数,这是一个坏主意.
我不确定你为什么要使用文件glob my $string = <$_[0]>.您是否期望在作为参数传递的文件名中使用通配符?如果是这样,那么你将打开并只读取第一个匹配的文件,否则不需要glob.
类似于$fh词条文件句柄的方式比裸字文件句柄更好FILE,并且当它们被销毁时将隐式关闭 - 通常在声明它们的块的末尾.
我不确定你的哈希是如何%counts填充的.没有正则表达式可以填补哈希值,但我必须相信你!
试试这个版本.熟悉Perl的人会感谢你(具有讽刺意味的是!)没有使用驼峰式变量名.并且很少看到main声明和调用的子例程.那是C,这是Perl.
更新我已更改此代码以执行原始正则表达式所做的操作.
use strict;
use warnings;
sub from_file {
my ($filename) = @_;
my $contents = do {
open my $fh, '<', $filename or die qq{Unable to open "$filename": $!};
local $/;
my $contents = <$fh>;
};
my %counts;
$counts{lc $1}++ while $contents =~ /(?=(\pL{2}))/g;
return \%counts;
}
sub main {
my $english_map = from_file('english.txt');
my $german_map = from_file('german.txt');
}
main();
Run Code Online (Sandbox Code Playgroud)