perl - 深度嵌套的 Perl 模块中仅供内部使用的类 - 避免尴尬的命名
问题描述
假设有一个名为 的 Perl 模块MyApplication/Subcomponent.pm
,并且像往常一样,文件以该模块开头,package MyApplication::Subcomponent;
该模块恰好定义了一组实用函数。其中一个实用功能需要创建一个本地的、仅供内部使用的类的实例。类定义非常简单,所以我将其粘贴在这里。它是一个RAII类,用于保存和恢复环境变量的值。
{
package MyApplication::Subcomponent::restore_ENV_THING;
sub DESTROY {
my $self = shift;
$ENV{THING} = ${ $self };
}
sub new {
my $class = shift;
my $old_value = $ENV{THING};
$ENV{THING} = shift;
return bless \$old_value, $class;
}
}
我的理解是,我必须在包名称的全局空间中为这个类命名,并且我必须从根开始命名:我不能只写package restore_ENV_THING;
,因为这会踩到命名空间的顶层。
所以这里的问题是:如果有的话,我能做些什么来使使用这个类的代码——保证与上面的代码块在同一个文件中,并且在词法上低于它——可以被编写
sub utility_routine_that_needs_to_save_and_restore_THING {
my $restorer = restore_ENV_THING->new($temporary_value);
...
}
代替
sub utility_routine_that_needs_to_save_and_restore_THING {
my $restorer = MyApplication::Subcomponent::restore_ENV_THING
->new($temporary_value);
...
}
如果您知道一个技巧,可以让我不必在包名称的全局空间中为类命名(也许与什么不完全不同open my $fh, ...
?)我也想听听。
请注意,MyApplication
它的代码有一些不寻常的限制:
- Perl 支持的最旧版本是 5.006。是的,你没看错,5.006。特别是这意味着我不能使用词法范围的 subs。
- 不得使用任何 CPAN 模块,只能使用自 5.006 起包含在标准库中的模块。这就是我不只使用Guard或Scope::Guard的原因,也是我使用原语手动定义类的原因。
- 无法发送任何 XS 代码本身。这就是我使用
sub DESTROY
RAII 的原因,即使在调用者中错误处理保护对象时它也无法正常工作;据我所知,如果不降到 C,就没有办法做得更好。
解决方案
包别名可以吗?
{
package MyApplication::Subcomponent::restore_ENV_THING;
BEGIN {
*MS:: = *MyApplication::Subcomponent::; # (initials for name)?
};
sub DESTROY {
my $self = shift;
$ENV{THING} = ${ $self };
}
sub new {
my $class = shift;
my $old_value = $ENV{THING};
$ENV{THING} = shift;
return bless \$old_value, $class;
}
}
现在它可以用作MS::restore_ENV_THING
.
这是所有包和范围的全局,是编译时别名。它确实与main::
符号表混在一起,但只要您选择一个“免费”名称就应该没问题。
还有一些包,比如aliased pragma、Package::Alias和其他一些包,但它们确实有一些微妙之处,所以我建议先阅读它们。每当我使用它时,我发现如上所示的内置别名是一个很好的解决方案。
推荐阅读
- python - 如何使用图像从 Nodejs 调用 tensorflow_model_server
- amazon-web-services - 如何在应用程序中使用 alexa voice sdk 或 api?
- javascript - 是否有同步 xhr 的替代方案,它提供了对用户输入的本地处理进行排队的功能?
- ruby-on-rails - 无法从 Rails 表单中检索参数
- python - 仅获取全年星期一的每小时平均值
- snowflake-cloud-data-platform - 重新安装 DUO 应用程序后,我需要重新启用 MFA
- javascript - 从 django 到 JS 的数据
- entity-framework - Blazor 服务器和实体框架。如何避免对数据库的多次冲突调用
- .net - o数据不区分大小写过滤器包含
- javascript - 如何将 ODATA 结果中的信息检索到 JavaScript 变量中?