2010-05-16 67 views
4

在我的Perl代碼中,我以前使用過以下兩種寫法,不鼓勵在現代perl:

# Style #1: Using & before calling a user-defined subroutine 
&name_of_subroutine($something, $something_else); 

# Style #2: Using ($$) to show the number of arguments in a user-defined sub 
sub name_of_subroutine($$) { 
    # the body of a subroutine taking two arguments. 
} 

由於知道這些樣式不建議我已經停止使用它們。

然而,出於好奇,我想知道以下幾點:

  • 什麼是這兩種寫作風格的由來? (我敢肯定,我自己並沒有夢想過這種風格。)
  • 爲什麼現代perl中的這兩種寫作風格不受歡迎?
  • 風格在某個時間點被認爲是最佳實踐嗎?
+1

所有已經討論過的SO:http://stackoverflow.com/questions/2056904 http:// stackoverflow。com/questions/297034 http://stackoverflow.com/questions/2485078 – daxim 2010-05-16 15:45:54

+1

[爲什麼Perl函數原型不好?](http://stackoverflow.com/questions/297034/why-are-perl-function- prototypes-bad) – Ether 2010-05-16 16:42:19

+2

由於'&foo(@args)'的使用覆蓋了原型,所以你會問這兩種常見的Perl特性濫用問題,這很具有諷刺意味。 – daotoad 2010-05-16 18:24:45

回答

15

&由於兩個原因,sigil不常用於現代Perl中的函數調用。首先,它很大程度上是多餘的,因爲Perl會考慮任何看起來像函數(隨後是parens)的函數。其次,執行&function()&function的方式有很大的不同,這可能會讓經驗較少的Perl程序員感到困惑。在第一種情況下,函數被調用時沒有參數。在第二種情況下,調用函數與當前@_(它甚至可以更改參數列表將被後來的語句在範圍中可以看出:

sub print_and_remove_first_arg {print 'first arg: ', shift, "\n"} 

sub test { 
    &print_and_remove_first_arg; 

    print "remaining args: @_\n"; 
} 

test 1, 2, 3; 

打印

first arg: 1 
remaining args: 2 3 

因此最終,對每個函數調用使用&最終隱藏了幾個&function;調用,這會導致難以發現的錯誤。另外,使用& sigil可以防止遵守函數原型,這在某些情況下很有用(如果您知道你在做什麼),但也可能導致困難追蹤錯誤。最終,&是功能行爲的強大修飾符,只應在需要該行爲時使用。

原型是相似的,它們的使用應該限制在現代Perl中。必須明確說明的是,Perl中的原型不是函數簽名。它們提示編譯器告訴它以與內置函數類似的方式解析對這些函數的調用。也就是說,原型中的每個符號都會告訴編譯器在參數上強加這種類型的上下文。此功能在定義類似於mappush或的函數時非常有用,它們的第一個參數與標準列表運算符的區別不同。

sub my_map (&@) {...} # first arg is either a block or explicit code reference 

my @ret = my_map {some_function($_)} 1 .. 10; 

原因原型sub ($$) {...}和類似用途都望而卻步,因爲9次了10年筆者的意思是「我想有兩個參數」,而不是「我希望每個有兩個參數與施加在調用點標量上下文」 。前者主張更好地寫着:

use Carp; 
sub needs2 { 
    @_ == 2 or croak 'needs2 takes 2 arguments'; 
    ... 
} 

這將然後允許如預期的那樣在呼叫風格的工作:

my @array = (2, 4); 

needs2 @array; 

綜上所述,無論是&印記和函數原型是有用和強大的工具,但只有在需要該功能時才能使用它們。他們多餘的使用(或誤用作參數驗證)會導致意外的行爲,並且很難追蹤錯誤。

+3

如果你投票回答,解釋爲什麼... – 2010-05-16 20:12:51

1

對於風格#1,&子程序之前只有必要的,如果你有一個共享的名稱和內建的子程序,你需要消除歧義,你想哪一個打電話,讓翻譯知道這是怎麼回事上。否則,相當於調用不含&的子程序。

既然如此,我會說它的使用是不鼓勵的,因爲你不應該命名你的子程序的名字與builtins的名字相同,並且在你調用它們之前定義你所有的子程序是很好的做法,的閱讀理解。除此之外,如果您在調用子程序之前先定義子程序,則可以省略括號,就像在內建中一樣。另外,只是直觀地講,在每個子程序前堅持&不必要地混淆了文件。

至於函數原型,事後他們被困在Perl中,並沒有真正做他們做的事情。從an article perl.com:

大多數情況下,原型比他們的價值更麻煩。首先,Perl不會檢查方法的原型,因爲這需要能夠在編譯時確定哪個類將處理該方法。因爲你可以在運行時改變@ISA - 你會發現問題。然而,主要原因是原型不太聰明。如果指定sub foo($$$),則不能將它傳遞給三個標量數組(這是vec()的問題)。相反,你必須說foo($ x [0],$ x [1],$ x [2]),這只是一個痛苦。

最後,最好是註釋你的代碼,以表明你打算讓子程序接受並自己進行參數檢查。正如文章所述,這對類方法實際上是必需的,因爲它們沒有參數檢查。

對於它的價值,Perl 6的補充形式參數列表,以這樣的語言:

sub do_something(Str $thing, Int $other) { 
    ... 
} 
+2

在文件中定義之前,您不必包括&當您進行子程序調用時。子程序名稱空間在編譯時填充。 – Brock 2010-05-16 13:07:27

+0

你是對的,我實際上正在考慮在調用之前放置聲明時忽略括號的能力。 http://oreilly.com/catalog/lperl3/chapter/ch04.html中的「省略&符號」給出了簡要說明。 – v64 2010-05-16 13:38:43

+0

這不就是爲什麼我們有'CORE :: func'嗎? – rjh 2010-05-16 13:55:33

3

在函數調用的&在Perl 4是強制性的,所以也許你有回升,最多從編程的Perl (1991)由拉里沃爾和蘭德爾施瓦茨,像我這樣做,或在某處類似。

至於函數原型,我的猜測是不合格的。也許你一直在模仿有意義的語言和/或強制聲明參數列表,並且因爲Perl中的函數原型看起來有點像參數列表,你已經開始添加它們了?

&功能不鼓勵,因爲它使代碼的可讀性,而不是必要的(在該情況下功能&是必要的是罕見的和往往更好避免)。

函數原型不是參數列表,所以大多數時候他們只會混淆讀者,或者讓你陷入僵化的錯覺,所以除非你確切地知道你是什麼,否則不需要使用它們。

&在Perl 4中是必需的,所以它們是最好的/必要的練習。我不認爲功能原型曾經是。

+3

你忘了提及使用sigil改變sub的調用方式。 '&foo(@args)'禁用原型。 '&foo'(無參數)將當前參數列表('_ _')直接傳遞給子例程。 – daotoad 2010-05-16 18:22:43