【问题标题】:How do I rename an exported function in Perl?如何在 Perl 中重命名导出的函数?
【发布时间】:2009-04-29 11:36:03
【问题描述】:

我有一些导出各种功能的 Perl 模块。 (我们已经有几年没有在新模块中使用 @EXPORT 了,但保留它是为了与旧脚本兼容。)

我已经重命名了一些函数和方法以更改为一致的命名策略,并认为然后添加一个列表行之类的

*directory_error      = *directoryError;

在模块的末尾只是将旧名称别名为新名称。

这有效,除非导出旧名称,并且调用脚本以非限定名称调用函数:在这种情况下,它报告未找到子例程(在调用模块中)。

我猜想发生的事情是,当别名尚未创建时,Exporter 在 BEGIN 中准备了列表;但我尝试将 typeglob 赋值放在 BEGIN 块中,但没有帮助。

我尝试过 AUTOLOAD,但当然这不会使该名称在调用上下文中可用。当然,我可以编写一系列包装函数,但这很乏味。我可能会自动生成包装函数,但我不确定如何。

有什么好的处理方法的建议吗?

【问题讨论】:

    标签: perl exporter typeglob


    【解决方案1】:

    导出

    手动调用@EXPORT =() 的东西有点憔悴了。

    package Bar;
    use strict;
    use warnings;
    
    use Sub::Exporter -setup => {
        exports => [qw[ foo ]],
        groups  => {
            default => [qw[ foo ]],
        }
    };
    
    sub foo(){
    
    };
    
    
    1;
    

    用途:

    use strict;
    use warnings;
    use Bar  foo => { -as-> 'Foo' }; 
    

    Sub::Exporter 可以做很多很棒的事情,比如组导出、组排除、构建器方法(即:它导出的 subs 的工作方式由传递的参数决定,subs 是在其他 subs 中生成的,等等)

    重命名

    对于重命名事物,最好有一个辅助函数,它只是作为一个遗留函数,当 Carp() 被调用时,它会推荐指向它的代码,以将其移至新方法。这将提高整个代码的一致性。

    然后,当您的测试停止发出警告时,您可以删除旧功能。

    sub old {  # line 1
       Carp::carp('Legacy function \'old\' called, please move to \'newmethod\' '); 
       goto &newmethod; # this passes @_ literally and hides itself from the stack trace. 
    } # line 4
    
    sub newmethod { # line 6
       Carp::cluck('In New Method'); 
       return 5;
    } # line 9
    
    print old(), "\n";  # line 11
    
    已调用旧函数“旧”,请移至 code.pl 第 2 行的“新方法” main::old() 在 code.pl 第 11 行调用 在 code.pl 第 7 行的新方法中 main::newmethod() 在 code.pl 第 11 行调用 5

    注意 newmethod 中的警告看起来与直接调用的完全一样。

    【讨论】:

      【解决方案2】:

      以下内容对我有用。这似乎是您所描述的;你一定是在什么地方弄错了。

      主脚本:

      use strict;
      use warnings;
      use Bar;
      
      baz();
      

      模块:

      package Bar;
      use strict;
      use warnings;
      
      require Exporter;
      our @ISA    = qw(Exporter);
      our @EXPORT = qw(baz);
      
      sub Baz { print "Baz() here\n" }
      
      *baz = *Baz;
      
      1;
      

      【讨论】:

      • 你是对的!它仍然无法正常工作(事实上,就您的示例而言,它是在说“未定义的子例程 Bar::baz”)但它必须是别的东西。感谢您的帮助。
      • 事实上,是同一个文件中有第二个包(另一件事我们不再做),而别名(*baz = *Baz)在错误的包中!找出另一个不将多个模块放在同一个文件中的原因。
      • 你想说的是“让 baz 成为一个子程序”,但 *baz = *Baz 是在说“让 $baz、@baz、%baz 等未定义并且 &baz 成为一个子程序”。 *baz = \&Baz 会更简洁,不太可能导致问题。比较: $ perl -le 'sub foo {42}; $bar = 10; *bar = \&foo;打印条();打印 $bar' 和: perl -le 'sub foo {42}; $bar = 10; *bar = *foo;打印条();打印 $bar'
      【解决方案3】:

      如果您希望两个名称都可见,则必须导出这两个名称。以迈克尔卡曼的回答为基础,您需要

      our @EXPORT = qw(Baz baz);
      

      our @EXPORT    = qw(Baz);
      our @EXPORT_OK = qw(baz);
      

      如果您希望能够调用程序中的任何一个。仅仅因为它们指向同一个 coderef 并不意味着该 coderef 的所有名称都会在一个时导出。

      【讨论】:

      • 如果我正确阅读了原始帖子@EXPORT(即无条件导出)只是为了向后兼容。据推测,依赖于此的用户仅使用旧名称。我猜测使用新名称的模块通过 @EXPORT_OK 或 %EXPORT_TAGS 显式导入它们。
      猜你喜欢
      • 1970-01-01
      • 2011-03-21
      • 2016-09-17
      • 2023-01-24
      • 2015-03-17
      • 1970-01-01
      • 2021-11-13
      • 2017-06-07
      • 2018-01-05
      相关资源
      最近更新 更多