试图通过Perl中的词法绑定本地化外部包变量
这是一个很长的标题,但是我恐怕我不能把一个词都去掉而不失去这个问题的真正含义。首先,我会快速描述一下我想要实现的目标,然后漫无目的地讲述我为什么希望这样做。如果你想按照问题的标题直接回答,请跳过漫无边际的问题:-) 快速描述 假设存在一个符合我要求的试图通过Perl中的词法绑定本地化外部包变量,perl,variables,internals,lexical-scope,Perl,Variables,Internals,Lexical Scope,这是一个很长的标题,但是我恐怕我不能把一个词都去掉而不失去这个问题的真正含义。首先,我会快速描述一下我想要实现的目标,然后漫无目的地讲述我为什么希望这样做。如果你想按照问题的标题直接回答,请跳过漫无边际的问题:-) 快速描述 假设存在一个符合我要求的词汇化内置代码,下面是: package Whatever; { lexicalize $Other::Package::var; local $var = 42; Other::Package->do_stuff; # depen
词汇化
内置代码,下面是:
package Whatever;
{
lexicalize $Other::Package::var;
local $var = 42;
Other::Package->do_stuff; # depends on that variable internally
}
为什么和为什么不
有一点背景知识,我正在白盒测试一个第三方模块
我希望变量本地化,因为我希望在测试转移到其他测试之前,只在有限的时间内对其进行更改<代码>本地是我发现的最好的方法,无需知道模块对初始值的选择
我想要一个词汇绑定,主要原因有两个:
我们的
,因为它不会从另一个包中获取变量:“在“我们的”中变量$Other::package::var不允许有包名。”“临时输入Other::package的作用域并不能阻止它:如果我使用块({package Other::package;我们的$var}
)那么绑定的持续时间不够长,无法发挥作用;如果我没有(package Other::package;我们的@var;package main
),那么我需要知道并复制上一个包的名称,这样可以防止代码移动过多
在问之前的问题之前做作业时,我发现词法::Var
,这似乎正是我所需要的。唉:“无法通过引用进行本地化。”
我也尽了最大的努力来理解基于我的*var
的表单,但总是遇到语法错误。今天,我学到了更多关于范围界定和绑定的知识:-)
我想不出为什么我想要的不可能,但我找不到正确的咒语。我是在要求一个不幸的未实施的edge案例吗?如果我没弄错,您所需要的就是我们的。如果我没有,请原谅我 下面是一个工作示例:
#!/usr/bin/env perl
use strict;
use warnings;
package Some;
our $var = 42;
sub do_stuff { return $var }
package main;
{
local $Some::var = 43;
print "Localized: " . Some->do_stuff() . "\n";
};
print "Normal: " . Some->do_stuff() . "\n";
但是如果您试图本地化某个包的private(
my
)变量,您可能做错了什么。我不太确定我是否理解正确。这有用吗
#!/usr/bin/env perl
{
package This;
use warnings; use strict;
our $var = 42;
sub do_stuff {
print "$var\n";
}
}
{
package That;
use warnings; use strict;
use Lexical::Alias;
local $This::var;
alias $This::var, my $var;
$var = 24;
print "$var\n";
This->do_stuff;
}
package main;
use warnings; use strict;
This->do_stuff;
有几种方法可以做到这一点:
- 鉴于:
{package Test::Pkg; our $var = 'init'; sub method {print "Test::Pkg::var = $var\n"} }
- 将包变量从当前包别名为目标包
{ package main; our $var; Test::Pkg->method; # Test::Pkg::var = init local *var = \local $Test::Pkg::var; # alias $var to a localized $Test::Pkg::var $var = 'new value'; Test::Pkg->method; # Test::Pkg::var = new value } Test::Pkg->method; # Test::Pkg::var = init
- 通过全局引用进行本地化:
{ package main; my $var = \*Test::Pkg::var; # globref to target the local Test::Pkg->method; # Test::Pkg::var = init local *$var = \'new value'; # fills the scalar slot of the glob Test::Pkg->method; # Test::Pkg::var = new value } Test::Pkg->method; # Test::Pkg::var = init
- 将词法绑定到目标包中,并将其溢出到当前包中:
{ package Test::Pkg; # in the target package our $var; # create the lexical name $var for $Test::Pkg::var package main; # enter main package, lexical still in scope Test::Pkg->method; # Test::Pkg::var = init local $var = 'new value'; Test::Pkg->method; # Test::Pkg::var = new value } Test::Pkg->method; # Test::Pkg::var = init
本地
非常有用:
no strict 'refs';
local ${'Some::Pkg::'.$name} = 'something';
use strict 'refs';
输出:
before: 23
during: 42
$Whatever::var is 42 inside the block
after: 23
$Whatever::var is undefined outside the block
local$Other::Package::var
在块的持续时间内临时将原始值设置为42,而local*var=\$Other::Package::var
在块的持续时间内临时将当前包中的$var
设置为$Other::Package::var
的别名
当然,这其中有些不符合
的严格要求,但我避免使用我们的
,因为我们的
会混淆问题,如果两个包都在同一个文件中(就像复制粘贴此示例时一样)我们的
声明可能会泄漏到它所使用的包中,进入同一文件中的以下包:)它确实有效:我目前已经在使用它的一个变体,因为缺少更好的东西。这不能满足我自己的要求的地方是它没有创建新的(较短的)词汇绑定:在块内部,我们坚持使用变量的完全限定的$Some::var
形式,而不是更好的普通$var
。我实际的包名比这个长了一点;这就是我首先提出问题的原因。旁注:这可能是您在一个代码示例中复制粘贴多个文件的副作用,但顶部附近的our$var=42
行可能会污染您以后想在目标块中尝试的任何内容。最好将包中的一些包装在块中。词法::别名。。。环顾四周时还没找到那个。看起来很有希望。尝试一下,我很快会告诉你的。有趣的东西。你只是让我对内部的理解比我想的多了一点。就我对问题的表述而言,它是有效的(因此我将投票并接受)。因为我太笨了,漏掉了太多,这并不是我想要的,但我现在只怪我自己。我漏掉的是:我的local
行实际上是local$pkg::var=f($pkg::var)
<代码>本地
必须在别名之前完成,否则它会破坏别名,所以我要写三次巨大的完全限定名,这比我的目标有点高。谢谢你的回答!这并不完全是我想要的,因为它将别名泄漏到了词法范围之外的*whater::var(我认为是whater中的helper函数)。谢谢你抽出时间来帮助我,非常感谢。@JB。啊,在这种情况下,词法::别名就是您想要的(正如Sinan所说)。我试图避免这种情况,因为这是一种狡猾的野兽。在霍布斯(SO order)之后阅读你的答案,同样的评论也适用。非常感谢你的帮助@JB.=>添加了一些不会污染名称空间的示例。您的第二个示例,除了提醒我不想重复的内容之外
before: 23
during: 42
$Whatever::var is 42 inside the block
after: 23
$Whatever::var is undefined outside the block