Perl 语句似乎已执行,但不知何故不是

问题描述 投票:0回答:2

可能这是一个愚蠢的问题,但我没有看到问题(假设必须有一个):

我写了一些代码;这是一个摘录:

use Getopt::Std;
my %options;
if (getopts('hty', \%options)) {
    my @opts = split(//, 'hty');

    @options{@opts} = (1, 1, 1)
        if (scalar (grep { defined } @options{@opts}) == 0);
    something()
      if ($options{'h'});
    #...
}

代码的目的是在三个选项均未设置的情况下将所有三个选项定义为已设置。 然而,即使设置了一个选项,代码似乎也被执行了(

-h
),而且最终值也不是我所期望的。 请参阅调试器会话的此片段:

DB<2> x %options
0 'h'
1 1
####: so `-h` was set
DB<3> n
main::(otptest.pl:298): if (scalar (grep { defined } @options{@opts}) == 0);
DB<3> n
main::(otptest.pl:297): @options{@opts} = (1, 1, 1)
###: surprisingly the assignment seems to be executed as well
DB<3> x %options
0 'y'
1 undef
2 'h'
3 1
4 't'
5 undef
###: However at the end the values are not `1` as expected, but `undef`

显然程序逻辑被该行为破坏了。 错误在哪里? 难道是 Perl 5.18.2 本身的错误?

perl conditional-statements optional-parameters
2个回答
4
投票

您看到的结果是由于 grep 中所有元素的自动生成:

use Data::Dumper;
my %options = qw(h 1);
print Dumper \%options;
print "empty\n" if  (scalar (grep { defined } @options{qw(h t y)}) == 0);
print Dumper \%options;

哪些输出:

$VAR1 = {
          'h' => '1'
        };
$VAR1 = {
          'y' => undef,
          'h' => '1',
          't' => undef
        };

grep 依次为其每个参数设置别名

$_
,这意味着可以通过分配给
$_
来修改参数。因此,perl 将参数视为在左值上下文中使用,并自动生成缺少的元素
$options{t}
$options{y}
.


0
投票

然而,即使设置了一个选项,代码似乎也被执行了

没有。如果是这样的话,这三个人都会有

1
的价值。

当它说它正在执行

@options{@opts} = (1, 1, 1)
时,它实际上是在执行
defined
grep
块)。这就是它执行 3 次的原因。

  DB<1> n
main::(a.pl:7):         if (scalar (grep { defined } @options{@opts}) == 0);
  DB<1> n
main::(a.pl:6):     @options{@opts} = (1, 1, 1)
  DB<1> n
main::(a.pl:6):     @options{@opts} = (1, 1, 1)
  DB<1> n
main::(a.pl:6):     @options{@opts} = (1, 1, 1)
  DB<1> n
main::(a.pl:8):     something()
main::(a.pl:9):       if ($options{'h'});
  DB<1> 

值是

undef
因为
grep
arg 列表是在左值上下文中评估的,以允许像

这样的东西
++$_ for grep { ... } ...;

这可以通过使用来避免

... if !grep { defined( $options{$_} ) } @opts;
© www.soinside.com 2019 - 2024. All rights reserved.