尝试通过 Perl 中的词法绑定本地化外部包变量
标题很长,但我恐怕一个字都删不掉,又不失问题的真正含义。我将首先快速描述我想要实现的目标,然后长篇大论地阐述为什么我希望以这种方式完成它。如果您打算直接回答问题标题,请跳过漫无目的的内容:-)
快速描述
假设存在一个 lexicalize
内置函数可以满足我的要求,这里是:
package Whatever;
{
lexicalize $Other::Package::var;
local $var = 42;
Other::Package->do_stuff; # depends on that variable internally
}
为什么和为什么
不在上下文中,我正在对第三方模块进行白盒测试。
我想要变量本地化,因为我希望它仅在有限的时间内发生变化,然后再进行其他测试。 local
是我发现执行此操作的最佳方法,无需依赖于了解模块对初始值的选择。
我想要一个词法绑定有两个主要原因:
- 我不想污染测试文件的更高级别的命名空间。
- 我想要比完全限定名称更短的名称。为了简洁起见,它没有出现在示例代码中,但我使用的标识符比显示的要多得多,并进行了相对于其先前值的计算和更新。
我无法正常使用 our
因为它不会从另一个包中获取变量:““our”中的变量 $Other::Package::var 不允许使用包名称。”作弊暂时进入 Other::Package 的范围并不会减少它:如果我使用块 ({ package Other::Package; our $var }
) 那么绑定不会持续足够长的时间有用;如果我不这样做(package Other::Package; our @var; package main
),那么我需要知道并复制前一个包的名称,这可以防止过多地移动该代码段。
在问这个问题的先前形式之前做功课时,我发现了 Lexical::Var
,这似乎正是我所需要的。唉:“无法通过参考进行本地化。”
我还尽了最大努力凭直觉感受基于 my *var
的表单,但不断遇到语法错误。今天,关于范围界定和绑定,我学到的东西比我关心的还要多:-)
我想不出为什么我想要的东西不可能实现的原因,但我找不到正确的咒语。我是否要求一个不幸的未实现的边缘情况?
It's a long title, but I'm afraid I can't take a single word out without losing the true meaning of the question. I'll give a quick description of what I'm trying to achieve first, then a long rambling on why I want it done this way. Skip the rambling if you intend to directly answer abiding with the question title :-)
Quick description
Assuming the existence of a lexicalize
builtin that does just what I want, here goes:
package Whatever;
{
lexicalize $Other::Package::var;
local $var = 42;
Other::Package->do_stuff; # depends on that variable internally
}
Whys and whynots
For a bit of context, I'm whitebox-testing a third-party module.
I want the variable localized because I want it changed for a limited time only, before the tests move on to something else. local
is the best way I found to do this without depending on knowing the module's choice for an initial value.
I want a lexical binding for two main reasons:
- I don't want to pollute the test file's higher-level namespace.
- I want something shorter than the fully-qualified name. It's not in the sample code for brevity, but I use the identifier a lot more than what's shown, with calculations and updates relative to its previous value.
I couldn't decently use our
because it won't grab a variable from another package: “No package name allowed for variable $Other::Package::var in "our".” Cheating to temporarily enter Other::Package's scope doesn't cut it: if I use a block ({ package Other::Package; our $var }
) then the binding doesn't last long enough to be useful; and if I don't (package Other::Package; our @var; package main
) then I need to know and copy the previous package's name, which prevents moving that piece of code around too much.
While doing my homework before asking a previous form of this question, I discovered Lexical::Var
, which seemed like it would be exactly what I needed. Alas: “Can't localize through a reference.”
I've also tried my best on my gut feeling of my *var
-based forms, but kept bumping into syntax errors. I've learned more than I cared to about scoping and binding today :-)
I can't think of a reason why what I want shouldn't be possible, but I can't find the right incantation. Am I asking for an unfortunate unimplemented edge case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果我没听错的话,你所需要的就是我们的。如果我不这样做,请原谅我。
这是工作示例:
但是如果您尝试本地化某些包的私有(
my
)变量,您可能做错了什么。If I get you right, all you need is our. Forgive me if I dont.
Here's working example:
But if you try to localize private (
my
) variable of some package, you probably doing something wrong.有几种方法可以做到这一点:
给出:
将当前包的包变量别名为目标包。
<前><代码>{
包主;
我们的 $var;
测试::Pkg->方法; # 测试::Pkg::var = init
本地 *var = \local $Test::Pkg::var;
# 将 $var 别名为本地化的 $Test::Pkg::var
$var = '新值';
测试::Pkg->方法; # Test::Pkg::var = 新值
}
测试::Pkg->方法; # 测试::Pkg::var = init
通过全局引用进行本地化:
<前><代码>{
包主;
我的 $var = \*Test::Pkg::var; # globref 以本地为目标
测试::Pkg->方法; # 测试::Pkg::var = init
local *$var = \'新值'; # 填充 glob 的标量槽
测试::Pkg->方法; # Test::Pkg::var = 新值
}
测试::Pkg->方法; # 测试::Pkg::var = init
绑定目标包中的词法,并让它溢出到当前包中:
<前><代码>{
包装测试::Pkg; # 目标包中
我们的 $var; # 为 $Test::Pkg::var 创建词法名称 $var
包主; # 进入主包,词法仍在范围内
测试::Pkg->方法; # 测试::Pkg::var = init
local $var = '新值';
测试::Pkg->方法; # Test::Pkg::var = 新值
}
测试::Pkg->方法; # 测试::Pkg::var = init
最后一个示例使用稍微尴尬的双包声明在一个包中创建词法并将其放入另一个包中。这个技巧对于其他场景中的
local
很有用:there are several ways to do this:
given:
alias a package variable from the current package to the target package.
localize through a glob reference:
bind a the lexical in the target package, and let it spill into the current package:
the last example uses a slightly awkward double package declaration to create a lexical in one package and get it into another. This trick is useful with
local
in other scenarios:我不太确定我的理解是否正确。这有帮助吗?
I am not quite sure if I understand you correctly. Does this help?
输出:
local $Other::Package::var
在块的持续时间内暂时将原始值设置为 42,并且local *var = \$Other::Package::var
code> 使当前包中的$var
在块的持续时间内临时成为$Other::Package::var
的别名。当然,其中一些不符合
严格
标准,但我避免使用our
,因为如果两个包都在同一个文件中,our
会混淆问题(如果您复制粘贴此示例,可能会出现这种情况)—our
声明可能会从它所使用的包中泄漏到同一文件中的以下包中:)Output:
local $Other::Package::var
makes the original value temporarily 42 for the duration of the block, andlocal *var = \$Other::Package::var
makes$var
in the current package an alias for$Other::Package::var
temporarily for the duration of the block.Naturally some of this isn't
strict
-compliant, but I avoided usingour
becauseour
obfuscates the issue if both packages are in the same file (as they might be if you copy-pasted this sample) — theour
declaration can leak out of the package it's used in, into a following package in the same file :)