“子程序外不能转到子程序”
我在子程序的顶部创建了一个名为“MENU”的子程序,名称为“INIT_MENU”,但当我打电话给该标签时出现错误:Can的子程序以外“吨转到子程序在program.pl线15“子程序外不能转到子程序”
下面是一个例子:
sub MENU {INIT_MENU: print "blah blah";}
和这里是线15:
goto &MENU, INIT_MENU;
很抱歉,如果它是一个重复的问题,我搜索在所有可能的地方,甚至在Perl
的goto只需要一个论证的官方网站,所以这段代码后的第一个执行goto &MENU
然后comma operator它在无效的上下文中评估常量INIT_MENU
(绘制警告)。
goto &NAME
的作用是用子程序NAME
替换遇到的子程序;在子程序之外调用它是没有意义的,这是一个错误。从perldiag
- 能子程序
(F)之外没有转到子程序的深深神奇的“转到子程序”呼叫只能更换一个子程序调用另一个。它不能用整块布来制造。总的来说,无论如何,你应该只从一个AUTOLOAD例程中调用它。请参阅goto。
上的这个用途的注释。
在goto LABEL
的harmfulness上写了很多。 †更不用说,当隐藏在例程中时,找不到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 post和this post。它在Perl中甚至更糟糕,因为对于goto
可以被认为是可接受的情况,存在特定的构造(和限制)。一个例子是跳出嵌套循环:Perl中有labels。
调度表的另一种替代方法是OO多态性。 – shawnhcorey
goto中尾随的INIT_MENU
是红鲱鱼 - 它在无效的情况下; Perl会发出警告,然后抛开价值。
问题出在goto &MENU
。这是一个不可思议的转换,它将用调用的子程序替换当前的子程序。这里的实质是替换当前的子程序。
您的代码在子程序之外调用goto &MENU
,所以没有当前的子程序被替换。 正好是错误信息描述的内容。
看起来没有足够的信息可用。试着看看你是否可以创建一个小例子。 – Suren
这里是[示例的完整源代码](https://pastebin.com/UWENBXZp),一个简单的程序。 –
我不知道你为什么要这样做,你可以删除块标签并调用你的MENU()。除非你知道你在做什么(以及为什么),否则你可能不需要使用典型的Perl代码中的'goto'。 – xxfelixxx