首页 > 解决方案 > 深度嵌套的 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它的代码有一些不寻常的限制:

标签: perlooppackage

解决方案


别名可以吗?

{
  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和其他一些包,但它们确实有一些微妙之处,所以我建议先阅读它们。每当我使用它时,我发现如上所示的内置别名是一个很好的解决方案。


推荐阅读