在perl中,我可以在子例程中动态创建变量吗? 背景
在我编写的代码中,我使用散列引用将数据传递到方法中(请参见注释[1]) 不幸的是,这会导致大量重复代码:在perl中,我可以在子例程中动态创建变量吗? 背景,perl,Perl,在我编写的代码中,我使用散列引用将数据传递到方法中(请参见注释[1]) 不幸的是,这会导致大量重复代码: sub thing { my ($self, $params) = @_; my ($foo, $bar, $baz, $biff,); if ( exists $params->{foo} && $params->{foo} ) { $foo = $params->{foo}; } # repeat for `bar`, `
sub thing {
my ($self, $params) = @_;
my ($foo, $bar, $baz, $biff,);
if ( exists $params->{foo} && $params->{foo} ) {
$foo = $params->{foo};
}
# repeat for `bar`, `baz`, `biff`
## rest of function ##
}
(并在每个带参数的函数中复制)
我想做什么
更简单的方法是定义一个参数列表,然后
迭代该列表,创建两个变量,并在需要时将其设置为值
为了测试这一点,我尝试:
my $params = { x => 1, y => 2};
my @params = qw(x y z a b c);
gno strict 'refs';
rep( ${$_}, @params );
use strict 'refs';
foreach my $p (@params) {
if ( exists $params->{$p} && $params->{$p} ) {
${$p} = $params->{$p};
}
}
print "x:$x, y:$y, z:$z, a:$a, b:$b, c:$c\n"
这给了我以下错误:
Global symbol "$x" requires explicit package name at ./test.pl line 20.
Global symbol "$y" requires explicit package name at ./test.pl line 20.
Global symbol "$z" requires explicit package name at ./test.pl line 20.
Global symbol "$c" requires explicit package name at ./test.pl line 20.
我可以创建动态变量吗?(如果是,怎么做?)
[1] 通过使用散列传递数据,我在许多方面获得了好处:
undef
值我使用了软引用:
#!perl
no strict "refs";
my %vars = ( x => 1, y => 2 );
for my $k ( keys %vars ) {
$$k = $vars{$k};
}
print $x, $y;
但是,建议的设置(使用strict;使用warnings;)阻止这种模式是有原因的。用它射自己的脚很容易。我是用软引用的:
#!perl
no strict "refs";
my %vars = ( x => 1, y => 2 );
for my $k ( keys %vars ) {
$$k = $vars{$k};
}
print $x, $y;
但是,建议的设置(使用strict;使用warnings;)阻止这种模式是有原因的。用它射自己的脚是很容易的。使用这样的符号引用是一个非常糟糕的主意。。。散列完全消除了这种需要
use warnings;
use strict;
my $params = { x => 1, y => 2, foo => 3, };
thing($params);
sub thing {
my $params = shift;
my $foo;
if (defined $params->{foo}){
$foo = $params->{foo};
}
print $foo;
}
您还可以直接传入散列本身(无论它是预创建的,还是内联传递给子对象。如果是预创建的,子对象将对副本进行操作)
使用这样的符号引用是一个非常糟糕的主意。。。散列完全消除了这种需要
use warnings;
use strict;
my $params = { x => 1, y => 2, foo => 3, };
thing($params);
sub thing {
my $params = shift;
my $foo;
if (defined $params->{foo}){
$foo = $params->{foo};
}
print $foo;
}
您还可以直接传入散列本身(无论它是预创建的,还是内联传递给子对象。如果是预创建的,子对象将对副本进行操作)
是的,您可以在Perl中执行此操作。但这是一个可怕的想法,因为马克·多米努斯(MarkDominus)在年解释了所有的原因 将这些值存储在散列中是一个更好的主意
#!/usr/bin/perl
use strict;
use warnings;
my $params = { x => 1, y => 2};
my @params = qw(x y z a b c);
my %var;
foreach my $p (@params) {
# You need to take care exactly what you want in this
# logical statement. The options are:
# 1/ $p exists in the hash
# exists $params->{$p}
# 2/ $p exists in the hash and has a defined value
# defined $params->{$p}
# 3/ $p exists in the hash and has a true value
# $params->{$p}
# I think the first option is most likely. The last one has
# good chance of introducing subtle bugs.
if ( exists $params->{$p} ) {
$var{$p} = $params->{$p};
}
}
print join ', ', map { "$_: " . ($var{$_} // 'undef') } @params;
print "\n";
是的,您可以在Perl中执行此操作。但这是一个可怕的想法,因为马克·多米努斯(MarkDominus)在年解释了所有的原因 将这些值存储在散列中是一个更好的主意
#!/usr/bin/perl
use strict;
use warnings;
my $params = { x => 1, y => 2};
my @params = qw(x y z a b c);
my %var;
foreach my $p (@params) {
# You need to take care exactly what you want in this
# logical statement. The options are:
# 1/ $p exists in the hash
# exists $params->{$p}
# 2/ $p exists in the hash and has a defined value
# defined $params->{$p}
# 3/ $p exists in the hash and has a true value
# $params->{$p}
# I think the first option is most likely. The last one has
# good chance of introducing subtle bugs.
if ( exists $params->{$p} ) {
$var{$p} = $params->{$p};
}
}
print join ', ', map { "$_: " . ($var{$_} // 'undef') } @params;
print "\n";
感谢Dave Cross和其他人-以下测试有效:
#!/usr/bin/perl
use strict;
use warnings;
use English qw( -no_match_vars ) ;
use Carp;
use Data::Dumper;
my $params = { x => 1, y => 2, z => 0};
my @params = qw(x y z a b c);
my %var;
foreach my $p (@params) {
if ( exists $params->{$p} ) {
$var{$p} = $params->{$p};
} else {
$var{$p} = undef;
}
}
print Dumper \%var;
这将为我提供%var
,其中包含所有所需参数(如@params
中所列),以及未传入的参数(即,不在$params
hashref中),这些参数是使用未定义的值创建的
因此,我可以自信地测试价值和真理,而不必担心存在
谢谢大家。感谢Dave Cross和其他人-以下测试有效:
#!/usr/bin/perl
use strict;
use warnings;
use English qw( -no_match_vars ) ;
use Carp;
use Data::Dumper;
my $params = { x => 1, y => 2, z => 0};
my @params = qw(x y z a b c);
my %var;
foreach my $p (@params) {
if ( exists $params->{$p} ) {
$var{$p} = $params->{$p};
} else {
$var{$p} = undef;
}
}
print Dumper \%var;
perl -Mstrict -MData::Dumper -wE'
{package Data::Dumper;our($Indent,$Sortkeys,$Terse,$Useqq)=(1)x4}
my @aok = qw( x y z a b c );
my %dft = ( a => -1 );
say "- - - -";
my $arg = { x => 1, y => 2, foo => 42 };
$arg = { %dft, %$arg };
say "arg: ", Dumper($arg);
my %var;
@var{ @aok } = @$arg{ @aok };
say "var: ", Dumper(\%var);
my %aok = map { $_ => 1 } @aok;
my @huh = grep !$aok{$_}, sort keys %$arg;
@huh and say "huh: ", Dumper(\@huh);
'
- - - -
arg: {
"a" => -1,
"foo" => 42,
"x" => 1,
"y" => 2
}
var: {
"a" => -1,
"b" => undef,
"c" => undef,
"x" => 1,
"y" => 2,
"z" => undef
}
huh: [
"foo"
]
这将为我提供%var
,其中包含所有所需参数(如@params
中所列),以及未传入的参数(即,不在$params
hashref中),这些参数是使用未定义的值创建的
因此,我可以自信地测试价值和真理,而不必担心存在
谢谢大家。这些都是警告,您没有声明变量$x、$y、$z、$c.@serenesat-我知道……这些是我试图从@params
列表动态创建的变量请参见@HåkonHægland Validate::params这件事很好……但是仍然需要创建一个变量列表,然后迭代每个poss[可能]设置标量值…这些是警告,您没有声明变量$x、$y、$z、$c.@serenesat-我知道…这些是我试图从@params
列表动态创建的变量请参见@HåkonHægland验证::params很好…但是仍然需要创建一个变量列表,然后在每个p上迭代可能的参数[可能]设置标量值…很有趣……。但是这让我没有可选参数-这意味着如果存在$foo
,我甚至不能做,更不用说如果定义了$foo
(是的,我很欣赏“脚踩洞”的机会):如果存在$foo
,您仍然可以执行。但是使用上述代码样式,$foo可以神奇地出现在生活中。有趣的是……。但是这让我没有可选参数-这意味着如果存在$foo
,我甚至无法执行,更不用说如果定义了$foo
(是的,我很欣赏“脚踩洞”的机会):)如果存在$foo,你仍然可以做。但是使用上面的代码样式,$foo可以神奇地出现在生活中。请注意,&&&$params->{$p}
将跳过任何不真实的值(零、空字符串等)是的,我在写我的答案时发现了这一点,但忘了修复它。更新了答案以澄清。耶-但是如果(存在$params->{$p}&&defined$params->{$p})
将修复它(顺便说一句,我自己的错误代码)注意&&&$params->{$p}
将跳过任何不真实的值(零,空字符串等),这可能是一个人想要的,也可能不是。Bugger。是的,我在写我的答案时发现了这一点,但忘了修复它。更新答案以澄清。耶-但是如果(存在$params->{$p}&&defined$params->{$p})
将修复这一点(附带的,我自己的坏代码)
perl -Mstrict -MData::Dumper -wE'
{package Data::Dumper;our($Indent,$Sortkeys,$Terse,$Useqq)=(1)x4}
my @aok = qw( x y z a b c );
my %dft = ( a => -1 );
say "- - - -";
my $arg = { x => 1, y => 2, foo => 42 };
$arg = { %dft, %$arg };
say "arg: ", Dumper($arg);
my %var;
@var{ @aok } = @$arg{ @aok };
say "var: ", Dumper(\%var);
my %aok = map { $_ => 1 } @aok;
my @huh = grep !$aok{$_}, sort keys %$arg;
@huh and say "huh: ", Dumper(\@huh);
'
- - - -
arg: {
"a" => -1,
"foo" => 42,
"x" => 1,
"y" => 2
}
var: {
"a" => -1,
"b" => undef,
"c" => undef,
"x" => 1,
"y" => 2,
"z" => undef
}
huh: [
"foo"
]