2014-09-12 38 views
7

我有一個while循環的程序,它有幾個點,其中某些條件需要採取一些動作,然後跳過剩餘的迭代。因爲這將始終是相同的代碼,我想把它放在一個子程序中,但是當我嘗試使用'next'時,作爲子文件中的最後一個語句,我得到了一個警告(通過下一個...的退出子例程),儘管它似乎按預期工作。從一個子程序結束一個循環迭代

即沒有子:

while (#condition) { 

    ## do stuff 

    if (#condition to skip iteration) { 
     ## action 
     next; 
    } 

    ## do more stuff, with the above block repeated several times 
} 

與子:

while (#condition) { 

    ## do stuff 

    &skip if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
    next; 
} 

在塊中的代碼的其餘部分/子很短,使得將所有但下;子語句中的語句幾乎無法使用子例程的對象。

我的問題是:

  • 是用 '未來;'在這樣的子程序中是好的,還是危險的/糟糕的做法?
  • 有沒有更好的方法從子程序中跳過其餘的迭代?
  • 如果確定並沒有更好的方法,是否有辦法抑制警告?

回答

4

您的警告本能可能是正確的。正如你所說,next只是不是一種嵌入子程序中的聲明。即使你不喜歡它,這是幾乎可以肯定更好:

while (#condition) { 

    ## do stuff 

    &skip, next if (#condition to skip iteration); 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
} 

(我正好有對非標準編程技術比較寬鬆的態度​​,特別是如果他們不濫用如果你感到強烈嵌入next。在這種情況下,我不會和你爭論,因爲這是你的程序,但是,既然你已經提出了建議,我同意你的直覺,即嵌入next可能不是一個好主意。)

+0

爲什麼在子跳過時使用圓括號?無需在這裏使用原型或簽名。也許不那麼容易混淆刪除它們。 – jmmeier 2014-09-14 14:33:12

3

如果這是一個好的做法,警告不會警告。使用你的功能,以便它返回的時間早,而不是next。您可以檢查函數的結果,並決定是否跳過下一次迭代,或無條件地跳到下一個,

use warnings; 

sub foo { 
    print ($_, "\n"); 
} 

for (1..10) { 
    foo(), next if $_ %2;; 
} 
6

學習Perl的第六版第179頁(腳註)

它可能不是一個好主意,但是你可以在子程序中使用這些循環控制 運算符來控制子程序之外的循環。也就是說,如果在循環塊中調用子程序 ,並且在子程序內沒有運行 的循環塊時子程序最後執行,則控制流將跳轉到主代碼中的 循環塊之後。 這種在子程序中使用來自 的循環控制的能力可能在未來版本的Perl中消失,和 可能會錯過它。

的解決方案可能是什麼已經說了別人,或者你可以在子做額外的測試,像

use strict; 
use warnings; 

while(<>) { 
    chomp; 
    maybeskip($_) && next if m/2/; #maybe skip if match 2 
    print "$_\n"; 
} 

sub maybeskip { 
    $_[0] !~ m/0/; #skip only if not match 0 
    # the sub retuns the result of the last executed expression 
    # if this is not wanted you should use explicit return $value; 
} 

seq 25 | perl script 

打印:

1 
3 
4 
5 
6 
7 
8 
9 
10 
11 
13 
14 
15 
16 
17 
18 
19 
20 

例如跳過所有匹配的2但不是20

8

這很容易抑制警告。只要將下面這行你next以上:

no warnings "exiting"; 

的警告是有原因的 - 在一個輔助子使用next一樣,可以是誰擁有讀碼旁邊的人混亂(誰可能是你在6個月的時間!),因爲next不會出現在循環塊的詞彙中。如果您剛剛讀取循環塊,則可能沒有注意到該文件後面的next;如果您只是閱讀子例程的定義,則可能不確定next的用途。您需要將兩部分代碼一起閱讀才能理解它。這使得它比直接在循環內部使用next更令人困惑。

此外,它限制了您剛剛定義的skip()子版的重用性。想要在另一個循環內重新使用那個skip()子?你最好希望跳躍邏輯在新循環中仍然有意義。

如果你已經考慮了所有這些,並且仍然想繼續,那麼就像我上面顯示的那樣禁用警告。 警告不是錯誤,它們只是警告。這就是爲什麼警告被稱爲「警告」。它們旨在將您的注意力引向潛在的問題;不要阻止你做出你認爲有用的事情。

3

可以通過將truthy返回到next並假裝繼續使用and運算符來將部分/全部跳過條件放入子例程中。

while (#condition) { 

    ## do stuff 

    &skip and next if (#condition to skip iteration); 

    ## or like this 
    next if (#condition to skip iteration) and &skip; 

    ## or like this 
    (#condition to skip iteration) and &skip and next; 

    ## do more stuff, with more calls to &skip 
} 

sub skip() { 
    ## action 
    return $common_skip_condition; 
}