DRY:Don’t repeat yourself,是編寫出優質代碼的一個重要原則。其含義就是不要四處寫同樣的代碼。簡言之,乾淨利落,是為“拽”(DRY)。
有些初學者喜歡把相同或類似功能的代碼四處粘貼,就屬於典型的self-repeat行為。這樣編寫代碼的一個顯著危害就是一旦你需要修改相應的代碼,你就得疲於奔命四處奔波地去修改每一處代碼。
即便如此,你心裡恐怕還難免惴惴不安,因為你很可能掛萬漏一。即使你確信已經全面沒有遺漏地進行了修改,你更沒底的事情是每處都進行了正確的修改。因為按照機率分析,如果你有99%把握做一次正確修改,那麼做十次正確修改不出錯的可能性就會下降到90%。
退一步說,你能保證四處修改都不失誤,四處修改所需要花費的精力也是驚人的(這一點在程式規模很小的時候不明顯,所以也很難被初學者所重視,正所謂“不吃一塹,不長一智”),你幾乎不太可能還有精力關注編程過程中更重要的事情——比如改進演算法等等。
即使沒有沒有上述種種弊端,最終你的代碼也一定臃腫不堪醜陋無比的。
所以任何一個合格程式員都懂得把相同功能的程式碼片段抽象為一個函數。在需要這些功能的地方只進行一次簡單的調用。這就避免了前面提到的種種弊端。
下面要談到的是另一種很不“乾爽”(DRY)即很“潮”的寫法,這種寫法“潮”在函數內多次重複相同的語句而顯得笨拙。
int main( void )
{
int n;
printf("please input the value of n: ");
scanf("%d",&n);
while(n<=0)
{
printf("error!");
printf("please input the value of n: ");
scanf("%d",&n);
}
/*其他語句*/
}
這段代碼的功能顯然是通過標準輸入裝置輸入n的值,如果輸入不是十進位正整數,則提示使用者並要求使用者重新輸入。
然而很明顯,在這個程式碼片段中
printf("please input the value of n: ");
scanf("%d",&n);
這兩句重複出現。
對於有的人來說,對此熟視無睹麻木不仁沒有任何感覺;對於另一些人來說,就如同看到作文中出現重複囉嗦的句子一樣會感到彆扭和不自然。這是一個境界的問題。而在後一種人當中有一部分知道如何修改,也有一部分人不清楚如何修改。本文就是為這部分有感覺但不清楚如何修改的人所做。治療麻木不仁感覺喪失的藥方我這裡沒有。
前面的代碼其實可以在不改變功能的前提下,改寫為:
while( printf("please input the value of n: ") , scanf("%d",&n) , n<=0 ) printf("error!");
這種寫法沒有任何多餘之處,比前一種寫法簡潔許多。下面對這種寫法的含義稍作解釋。
我們知道,C語言while語句的一般形式為
while(運算式)
語句
這裡的“運算式”只要是標量類型(scalar type)就可以。第二種寫法中while關鍵字後()內的運算式是一個逗號運算式,其值的類型為子運算式“n<=0”的類型,而“n<=0”的類型無疑屬於標量類型,因而第二種寫法滿足C語言的文法要求。
這個逗號運算式的求值過程是:(1)求printf("please input the value of n: ")這個函數調用運算式的值,然而在這裡我們並不需要也不使用這個值。在求值過程中會伴隨有相應的副效應(side effect)——在標準輸出裝置上輸出“please input the valueof n: ”這一字元序列,這才是我們所需要的。(2)求函數調用運算式scanf("%d",&n)的值,這個值我們同樣不需要。我們所需要的依然是函數調用運算式scanf("%d",&n)的副效應,其中最重要的副效應是,變數n得到了一個新的值。(3)緊接著,由於變數n通過輸入有了有意義的值,就可以求“n<=0”這個子運算式的值了,這個值是執行while語句所需要的。這個值也是第二種寫法和第一種寫法等價的必要條件之一。另一個必要條件是printf("please input the value of n: "),scanf("%d",&n)及printf("error!")這幾個函數調用副效應出現的次序相同,由於逗號運算式運算規則對求值次序的規定,這種次序同樣得到了保證。
其他表現力不強的語言(比如BASIC)可能必須使用第一種方法寫代碼,那是由於語言自身的局限,是沒有辦法的事。但是對於C語言來說,完成同樣的功能卻完全可以寫的更加瀟洒飄逸。這主要歸功於C語言強大功能的運算式。
由於C語言運算式功能的強大,對於更高的功能要求,這種寫法同樣奏效。比如,假如要求輸入的不是正數或其他非法輸入(如輸入了非十進位字元)時,皆提示使用者並要求使用者重新輸入,則代碼可以寫成:
while( printf("please input the value of n: ") , scanf("%d",&n)==0 || n<=0 ) { //一些必要的處理 }
當輸入不滿足%d格式要求時,scanf()調用結束且傳回值為0。這裡,“,”和“&&”共同保證了必要的順序。
至於,前面第一種、第二種寫法究竟哪一個好,這個問題還是留給您自己吧。凡是價值判斷可能都免不了要帶有一些主觀色彩。更何況,根據我的經驗,一旦你提出吃飯應該用飯碗的時候,必定會有很多用痰盂吃飯的衝上前來,和你激辯用痰盂吃飯也是完全可以的。
如果有人喜歡並堅持用痰盂吃飯,關我屁事!