我已经创建了一个名为“MENU”的子程序,在子程序的顶部有一个名为“INIT_MENU”的标签,但是当我调用这个标签时出现错误:无法在子程序之外转到子程序program.pl第15行
以下是一个例子:
sub MENU {INIT_MENU: print "blah blah";}
,这是第15行:
goto &MENU, INIT_MENU;
很抱歉,如果这是一个重复的问题,我搜索了所有可能的地方,甚至在Perl的官方网站
答案 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
,可能需要重新考虑(部分)设计。
†例如,请参阅goto和this post。它在Perl中(甚至)更糟,因为在goto
可以被认为可接受的情况下存在特定的构造(和限制)。一个例子是跳出嵌套循环:Perl中有this post。