“子程序外不能转到子程序”

“子程序外不能转到子程序”

问题描述:

我在子程序的顶部创建了一个名为“MENU”的子程序,名称为“INIT_MENU”,但当我打电话给该标签时出现错误:Can的子程序以外“吨转到子程序在program.pl线15“子程序外不能转到子程序”

下面是一个例子:

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

和这里是线15:

goto &MENU, INIT_MENU; 

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

+0

看起来没有足够的信息可用。试着看看你是否可以创建一个小例子。 – Suren

+0

这里是[示例的完整源代码](https://pastebin.com/UWENBXZp),一个简单的程序。 –

+0

我不知道你为什么要这样做,你可以删除块标签并调用你的MENU()。除非你知道你在做什么(以及为什么),否则你可能不需要使用典型的Perl代码中的'goto'。 – xxfelixxx

goto只需要一个论证的官方网站,所以这段代码后的第一个执行goto &MENU然后comma operator它在无效的上下文中评估常量INIT_MENU(绘制警告)。

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

  • 能子程序

(F)之外没有转到子程序的深深神奇的“转到子程序”呼叫只能更换一个子程序调用另一个。它不能用整块布来制造。总的来说,无论如何,你应该只从一个AUTOLOAD例程中调用它。请参阅goto


上的这个用途的注释。

goto LABELharmfulness上写了很多。 †更不用说,当隐藏在例程中时,找不到INIT_MENU:。结果是总有其他更好的方法。

采样器

  • 调用函数如果由于某种原因,你想 '隐藏' 如预期

    调用MENU使用goto &MENU传递参数

    MENU(INIT_MENU); 
    
    sub MENU { 
        my $menu = shift; 
        if ($menu eq 'INIT_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(例如)以触发所选块。在此之后,“甚至不会caller将能够告诉该例程被称为第一,”见goto。但这通常是不需要的。

  • 为什么即使有MENU()?相反,在单独的子文件中有菜单选项,并且它们的引用可以是散列中的值,其中键是选项的名称。所以,你就会有一个分派表和逻辑(或用户选择)后,选择其代码运行的菜单项直接

    my %do_menu_item = (INIT_MENU => sub { code for INIT_MENU }, ...); 
    ... 
    $do_menu_item{$item_name}->(); 
    
  • 菜单系统往往具有发展壮大规模,更复杂。从一开始就采用面向对象是有意义的,然后还有其他方法可以用于这个细节。

如果你发现自己考虑goto可能是时候重新考虑(一些)的设计。


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

+0

调度表的另一种替代方法是OO多态性。 – shawnhcorey

goto中尾随的INIT_MENU是红鲱鱼 - 它在无效的情况下; Perl会发出警告,然后抛开价值。

问题出在goto &MENU。这是一个不可思议的转换,它将用调用的子程序替换当前的子程序。这里的实质是替换当前的子程序

您的代码在子程序之外调用goto &MENU,所以没有当前的子程序被替换。 正好是错误信息描述的内容。