在深度嵌套的 Perl 模块中仅供内部使用 class - 避免笨拙的命名

Internal-use-only class in a deeply nested Perl module - avoiding awkward naming

假设一个名为 MyApplication/Subcomponent.pm 的 Perl 模块,并且文件通常以 package MyApplication::Subcomponent; 开头,这个模块恰好定义了一组实用函数。其中一个实用函数需要创建一个本地的、仅供内部使用的实例 class。 class 的定义非常简单,所以我将其粘贴在这里。是一个RAIIclass保存和恢复环境变量的值

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

我的理解是我必须在包名的全局space中给这个class一个名字,而且我必须从根开始命名它:我不能只写package restore_ENV_THING; 因为那会影响 namespace.

top 级别

所以这里的问题是:如果有的话,我可以做什么,以便 使用 这个 class 的代码——保证在同一个文件作为上面的代码块和它下面的词法 - 可以写成

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

如果你知道一个技巧可以让我必须给class包名的全局space一个名字(也许与 open my $fh, ... 的做法并不完全不同?)我也想听听。


请注意 MyApplication 对其代码有一些不寻常的限制:

包裹 alias 可以吗?

{
  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:: 符号 table 混为一谈,但只要您选择一个“免费”名称就可以了。

然后是包,例如 aliased pragma, Package::Alias,以及许多其他包,但它们确实具有微妙之处,因此我建议您先阅读它们。每当我使用它时,我发现如上所示的内置别名是一个很好的解决方案。

MyApplication::Subcomponent::restore_ENV_THING->new($temporary_value);

的缩写
"MyApplication::Subcomponent::restore_ENV_THING"->new($temporary_value);

所以你只需要

use constant restore_ENV_THING => "MyApplication::Subcomponent::restore_ENV_THING";

restore_ENV_THING->new($temporary_value);