我很沮丧。 好,所以这可能是最大的 乐趣 珀尔 我发现的错误。即使在今天,我正在学习有关Perl的新知识。本质上,触发器操作员 .. 返回 错误的 直到左侧返回 真的, , 接着 真的 直到右侧返回 错误的 保持全球状态(或者这是我认为的。)

我可以重设吗?也许这是Perl 4型几乎没有使用过 reset())?或者,是否没有办法安全地使用此操作员?

我也看不到这个(全局上下文位)在任何地方记录的 perldoc perlop 这是一个错误吗?

代码

use feature ':5.10';
use strict;
use warnings;

sub search {
    my $arr = shift;
    grep { !( /start/ .. /never_exist/ ) } @$arr;
}

my @foo = qw/foo bar start baz end quz quz/;
my @bar = qw/foo bar start baz end quz quz/;

say 'first shot - foo';
say for search \@foo;

say 'second shot - bar';
say for search \@bar;

扰流板

$ perl test.pl
first shot
foo
bar
second shot
有帮助吗?

解决方案

有人可以澄清文档的问题是什么?它清楚地表明:

Each ".." operator maintains its own boolean state.

关于“每个”的含义有些模糊,但是我认为复杂的解释不会很好地提供文档。

请注意,Perl的其他迭代器(each 或标量上下文 glob)可能导致同样的问题。因为国家 each 与特定的哈希绑定,而不是特定的代码,each 可以通过调用(即使在无效上下文中)重置 keys 在哈希上。但对于 glob 或者 .., ,除了调用迭代器之前,没有可用的重置机制,直到重置为止。示例地球错误:

sub globme {
    print "globbing $_[0]:\n";
    print "got: ".glob("{$_[0]}")."\n" for 1..2;
}
globme("a,b,c");
globme("d,e,f");
__END__
globbing a,b,c:
got: a
got: b
globbing d,e,f:
got: c
Use of uninitialized value in concatenation (.) or string at - line 3.
got: 

对于过于好奇的是,这里有一些示例,其中相同。 不同的 .. 操作员:

单独关闭:

sub make_closure {
    my $x;
    return sub {
        $x if 0;  # Look, ma, I'm a closure
        scalar( $^O..!$^O ); # handy values of true..false that don't trigger ..'s implicit comparison to $.
    }
}
print make_closure()->(), make_closure()->();
__END__
11

评论 $x if 0 线以查看非关闭有一个。所有“副本”共享的操作,输出为 12.

线程:

use threads;
sub coderef { sub { scalar( $^O..!$^O ) } }
coderef()->();
print threads->create( coderef() )->join(), threads->create( coderef() )->join();
__END__
22

线程代码从..在线程创建之前的状态开始,但线程中其状态的变化与其他任何事物的影响都隔离开来。

递归:

sub flopme {
    my $recurse = $_[0];
    flopme($recurse-1) if $recurse;
    print " "x$recurse, scalar( $^O..!$^O ), "\n";
    flopme($recurse-1) if $recurse;
}
flopme(2)
__END__
1
 1
2
  1
3
 2
4

递归的每个深度都是一个单独的..操作员。

其他提示

诀窍是不使用相同 拖鞋 因此,您无需担心。只需制作一个发电机功能,就可以为您提供一个新的子例程,并使用新的触发器,您只使用一次:

sub make_search {
    my( $left, $right ) = @_;
    sub {
        grep { !( /\Q$left\E/ .. /\Q$right\E/ ) } @{$_[0]};
        }
}

my $search_sub1 = make_search( 'start', 'never_existed' );
my $search_sub2 = make_search( 'start', 'never_existed' );


my @foo = qw/foo bar start baz end quz quz/;

my $count1 = $search_sub1->( \@foo );
my $count2 = $search_sub2->( \@foo );

print "count1 $count1 and count2 $count2\n";

我也在 制作独家触发器运算符.

“范围操作员” .. 记录在中 Perlop 在“范围操作员”下。浏览doucmentation,看来没有任何方法可以重置状态 .. 操作员。每个实例 .. 操作员保持其状态 自己的 状态,这意味着没有任何方法可以参考任何特定的状态 .. 操作员。

看起来它是为非常小的脚本而设计的,例如:

if (101 .. 200) { print; }

文档指出,这是简短的

if ($. == 101 .. $. == 200) { print; }

以某种方式使用 $. 在那里是隐含的(Toolic在评论中也指出了它也记录下来的)。这个想法似乎是这个循环运行 一次 (直到 $. == 200)在perl解释器的给定实例中,因此您不必担心重置状态 .. 拖鞋。

由于您确定的原因,该操作员似乎在更一般的可重复使用上下文中并不太用。

针对您特定情况的解决方法/hack/欺骗是将最终值附加到您的数组:

sub search { 
  my $arr = shift;
  grep { !( /start/ .. /never_exist/ ) } @$arr, 'never_exist';
} 

这将确保范围运营商的RHS最终将是真实的。

当然,这绝不是一般解决方案。

我认为,这种行为尚未清楚地记录下来。如果您可以构建明确的解释,则可以将补丁应用于 perlop.pod 通过 perlbug.

我发现了这个问题,据我所知,没有办法解决它。结果是 - 不要使用 .. 运算符在函数中,除非您确定在离开功能时将其留在错误状态,否则该功能可能会返回相同输入的不同输出(或对同一输入显示不同的行为)。

每次使用 .. 操作员保持自己的状态。就像亚历克斯·布朗(Alex Brown)所说的那样,当您离开功能时,您需要将其留在虚假状态。也许您可以做类似的事情:

sub search {
  my $arr = shift;
  grep { !( /start/ || $_ eq "my magic reset string" ..
            /never_exist/ || $_ eq "my magic reset string" ) } 
      (@$arr, "my magic reset string");
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top