2017-10-22 111 views
1

我在子程序的頂部創建了一個名爲「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

回答

5

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

2

goto中尾隨的INIT_MENU是紅鯡魚 - 它在無效的情況下; Perl會發出警告,然後拋開價值。

問題出在goto &MENU。這是一個不可思議的轉換,它將用調用的子程序替換當前的子程序。這裏的實質是替換當前的子程序

您的代碼在子程序之外調用goto &MENU,所以沒有當前的子程序被替換。 正好是錯誤信息描述的內容。