微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Perl尽可能干净地调用具有显式附加范围的子例程引用

我希望能够写出如下内容……

call_with_scope({
    x => 47,},sub {
    printf "$x\n";
    printf "$y\n";
});

其中$y绑定在包含表达式的环境中(词法或动态,具体取决于符号).

我找到了一种方法,但它不需要在包含call_with_scope(…)的表达式中生效严格的“变量”,并且call_with_scope的实现在将控制转移到回调之前使用eval创建本地绑定.

有没有办法避免在调用站点要求没有严格的“变量”,或者在不诉诸eval的情况下引用和更改局部变量的值?

为了完整起见,下面的代码片段实现了call_with_scope并打印47然后打印48.

#!/usr/bin/env perl
use strict;
use warnings;

sub call_with_scope {
    my ($env,$func) = @_;
    my %property;
    my @preamble;
    foreach my $k (keys %$env) {
        $property{$k} = $env->{$k};
        # deliberately omitted: logic to ensure that ${$k} is a well-formed variable
        push @preamble,"local \$$k = \$property{'$k'};";
    }
    # force scalar context
    do {
        my $str = join('','no strict "vars";',@preamble,'$_[1]->();');
        return scalar(eval($str));
    };
}                        

do {
    no strict 'vars';
    local $x;
    my $y = 48;
    call_with_scope(
        {
            x => 47,sub {
            printf "$x\n";
            printf "$y\n";
        }
    );
};

解决方法

I’m trying to write something kind of like Test::LectroTest … except that instead of using a source filter and comments like in Property { ##[ x <- Int,y <- Int ]## <body> } … I want to write something like Property({x => gen_int,y => gen_int},sub { <body> }) where $x and $y inside body get their values when an “instantiation” of a property test is performed.

您可以通过在调用者的包中将$x和$y定义为全局变量来实现此目的.

no strict 'refs';
my $caller = caller;
for my $var (keys %$properties) {
    *{$caller.'::'.$var} = $properties->{$var};
}
$code->();

但这不容易本地化.使用全局变量污染调用者的命名空间可能会导致测试之间出现神秘的数据泄露.通常,在测试库中使用尽可能少的魔法;用户将有足够的自己奇怪的魔法来调试.

相反,提供一个返回属性函数.例如,p.

package LectroTest;

use Exporter qw(import);
our @EXPORT = qw(test p);
our $P;

sub test {
    my($props,$test) = @_;

    local $P = $props;
    $test->();
}

sub p {
    return $P;
}

测试看起来像:

use LectroTest;

test(
    { x => 42 },sub { print p->{x} }
);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐