加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-16 06:07:01 所属栏目:大数据 来源:网络整理
导读:我希望能够写出如下内容…… call_with_scope({ x = 47,},sub { printf "$xn"; printf "$yn";}); 其中$y绑定在包含表达式的环境中(词法或动态,具体取决于符号). 我找到了一种方法,但它不需要在包含call_with_scope(…)的表达式中生效严格的“变量”,并且ca
我希望能够写出如下内容……

call_with_scope({
    x => 47,},sub {
    printf "$xn";
    printf "$yn";
});

其中$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 "$xn";
            printf "$yn";
        }
    );
};

解决方法

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} }
);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读