“无法在子程序之外转到子程序”

时间:2017-10-22 03:20:44

标签: perl label subroutine goto

我已经创建了一个名为“MENU”的子程序,在子程序的顶部有一个名为“INIT_MENU”的标签,但是当我调用这个标签时出现错误:无法在子程序之外转到子程序program.pl第15行

以下是一个例子:

sub MENU {INIT_MENU: print "blah blah";}

,这是第15行:

goto &MENU, INIT_MENU;

很抱歉,如果这是一个重复的问题,我搜索了所有可能的地方,甚至在Perl的官方网站

1 个答案:

答案 0 :(得分:5)

goto需要一个参数,因此该代码首先执行goto &MENU,然后在comma operator之后评估void上下文中的常量INIT_MENU(绘制警告)。

goto &NAME的目的是用子例程NAME替换遇到它的子例程;在子程序之外调用它是没有意义的,这是一个错误。来自perldiag

  
      
  • 无法转到子程序外的子程序
  •   
     

(F)深刻神奇的“goto子程序”调用只能替换另一个子程序调用。它不能用整块布制造一块。通常,您应该仅使用AUTOLOAD例程调用它。请参阅goto

对此目的的评论。

goto LABEL的{​​{3}}上写了很多。更不用说隐藏在例程中时找不到INIT_MENU:。结果是总有其他更好的方法。

采样器

  • 调用该函数并传递参数

    MENU(INIT_MENU);
    
    sub MENU {
        my $menu = shift;
        if ($menu eq 'INIT_MENU') { ... }
        ...
    }
    
  • 如果出于某种原因,您希望“隐藏”对MENU的调用,请按预期使用goto &MENU

    sub top_level {   # pass INIT_MENU to this sub
        ...
        goto &MENU;   # also passes its @_ as it is at this point
    
        # the control doesn't return here; MENU took place of this sub
    }
    

    这将top_level()全部替换为MENU(),并将@_传递给它。然后如上所述处理MENU中的输入(例如)以触发所选择的块。在此“ not even harmfulness将能够告诉该例程首先被调用之后,”请参阅caller。但这通常是不必要的。

  • 为什么甚至有MENU()?相反,在单独的subs中有菜单选项,它们的引用可以是散列中的值,其中键是选项的名称。所以你有一个调度表,在逻辑(或用户选择)选择一个菜单项后,它的代码直接运行

    my %do_menu_item = ( INIT_MENU => sub { code for INIT_MENU }, ... );
    ...
    $do_menu_item{$item_name}->();
    
  • 菜单系统往往随着开发变得越来越大,越来越复杂。从一开始就采用OO是有意义的,然后还有其他方法来处理这个细节。

如果您发现自己正在考虑goto,可能需要重新考虑(部分)设计。

例如,请参阅gotothis post。它在Perl中(甚至)更糟,因为在goto可以被认为可接受的情况下存在特定的构造(和限制)。一个例子是跳出嵌套循环:Perl中有this post