Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.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,在我编写的代码中,我使用散列引用将数据传递到方法中(请参见注释[1]) 不幸的是,这会导致大量重复代码: sub thing { my ($self, $params) = @_; my ($foo, $bar, $baz, $biff,); if ( exists $params->{foo} && $params->{foo} ) { $foo = $params->{foo}; } # repeat for `bar`, `

在我编写的代码中,我使用散列引用将数据传递到方法中(请参见注释[1])

不幸的是,这会导致大量重复代码:

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
  • 我传递的数据更少:1个标量(一个引用)而不是多个标量
  • (我接受函数能够更改父级数据的危险,而不是乱搞它的副本……)

  • 我使用了软引用:

    #!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"
    ]