從閱讀代碼上考慮,if里的">"、"<"用哪個更容易看懂?
輪子哥說的不錯,大家沒人看過《代碼大全》嘛,裡面說的有,輪子哥的這種用法是最推薦的
這種類型的規範只要統一使用一種就行,沒有大的影響。別這塊代碼用這個風格,另一塊代碼用另一個風格,那就很糟糕。一致性很重要!
如果單論可讀性與合理性,其實沒有if更容易看懂。我們舉個極端點的例子:
按照學生分數給出評價,&>90=A、&>80=B、&>70=C、&>60=D、~=E
這個題目,最直觀的數學表達應是這樣的:
0 -E-&> 60 -D-&> 70 -C-&> 80 -B-&> 90 -A-&> 100
諾,這麼一條坐標軸是不是非常直觀明了?但為什麼到了代碼里,我們卻都寫成了這樣:
level = {
if (score &> 90 {
:A
} else if (score &> 80) (
:B
} else if (score &> 70) {
:C
} else if (score &> 60) {
} else {
:E
}
}
這還是連續分段情況,如果不連續,比如:
水槽情況預警,要求:低於水位線20或高於水位線30時給出警告,低於30高於40給出錯誤
數學坐標軸:
-00 -ERROR-&> -30 -:WARNING-&> -20 -&> 0 -&> +30 -:WARNING-&> +40 -ERROR-&> +00
到了代碼里就更丑了:
status = {
if (hight &< -30 or hight &> 40) {
:ERROR
} else if (hight &< -20 or hight &> 30) {
::WARNING
} else {
:nil
}
}
這尼瑪啥玩意兒?這叫可讀性?無論你是 (h &< -a || h &> +b) 還是 (h &< -a || +b &< h) 還是 (h &> +b || -a &> h) 都一樣噁心(當然這些中我更推崇第二種,畢竟好歹也體現了一點直觀坐標軸)。
那麼我們該怎麼Coding更好呢?為了簡單起見,先看第一例:
score =&>
arrive(point) = point &> score
index = [60, 70, 80, 90, 100].index(arrive)
level = [:E, :D, :C, :B, :A][index]
=&> level
ok,簡單明了,我讀給你看:1. 輸入score,2. arrive的真值等價於某個point大於給定score,3. index的值等於坐標軸上找到arrive(為真)的位置,4. level的值為index對應位置上的原子, 4. 輸出level。整個代碼塊的職責:輸入score,找到score的level,輸出level。
可以看到除去添加輸入輸出與一些更嚴明的界定,思想與數學基本保持了一致性。
更進一步,我們去掉硬編碼:
score =&>
arrive(point) = point &> score
index = range(60, 100, 10).index(arrive)
level = range(E, A, -1)[index]
=&> level
再進一步,我們保持編碼內信息正交 (主要是range(60, 100, 10)與range(E, A, -1)這兩組,其實交叉了「分五個等級」這個硬編碼的信息)
(score, limit=5) =&>
arrive(point) = score &> point
index = 100..0 |&> step(-10) |&> take(limit) |&> index(arrive) |&> else(limit-1)
level = A..Z |&> step(1) |&> take(limit) |&> fetch(index)
=&> level
好吧可讀性又變差了,但功能其實加強了,現在整個代碼塊可以簡單的讀作:輸入score與可選的、默認為5的limit,找到limit段數內score的level段,輸出level。
(這個例子我著重修改了一下,來表現函數式的魅力,比如index行現在可讀多了:100到0範圍內,步進為-10,取前limit個,找到arrive的位置,找不到則為limit-1)
更進一步,我們可以對第一個range的三參(-10)和第二個range的三參(1)進行提取,因為這兩個參數實際隱含了「10分數跨度對應1等級」這個信息。具體例子我就不寫了。
(因為例子修改了,現在不是三參了。之前的range(start, end, step)的格式三參實際是現在的step。所以我這裡其實可以直接說:「我們可以對step進行提取」這樣。但我保留之前的說法,就是為了展示什麼就叫可讀性。)
我們來考慮另外一個問題,這段編碼中有一個中間變數 "index" ,這個變數是有必要的嗎?不是。因為我們的數學坐標軸上沒有它。仔細看數學表達,「0 -E-&> 60 -D-&> 70 -C-&> 80 -B-&> 90 -A-&> 100」,發現了嗎?字母與數字混在了一起。到了代碼里,我們其實把他們分開了,數字組編碼為index行,字母組編碼為level行。這是對一些編程語言,特別是早期面向機器的一些語言的「同構數組|列表」做出的妥協。但其實現在很多高級編程語言越來越面向人類了,異構數組|列表是支持的(多大點事兒嘛)。那麼我們的Code又有新范兒了:
score =&>
arrive([level, point]) = point &> score level
level = [(:E, 60), (:D, 70), (:C, 80), (:B, 90), (:A, 100)].find(arrive)
=&> level
(哦不對,這還是同構的,是tuple&的同構list,但是tuple是異構的。真異構應該這麼寫:"[:E, 60, :D, 70, :C, 80, :B, 90, :A, 100] |&> unzip(2)",看起來更接近坐標軸了,但有點過度刻意追求了)
同樣的,level行的那個硬編碼的映射表可以優化:
level = [(A+i, 100-10*i) | i in 0..5].find(arrive)
不熟悉這種編程風格的人第一眼就會覺得好恐怖,於是潛意識就不讀了,但其實只要你理解其思想,數學又學的不錯(不錯就行,只要你有高中水平的數學知識,這行里的什麼列表推導、二元組之類的真*高級語言概念都應該天然理解),就會發現這樣的編碼極為可讀,數學的魅力就在於符號化的表達,邏輯嚴謹又簡潔有力,這其實才是我心目中的可讀性,畢竟程序是重邏輯的。但如果你的代碼重業務,還是不要做到這一步,畢竟什麼東西過度了都不太好(尤其你參與的是一群碼農合作的項目時,這麼寫小心別人打屎你。不過一般來說這種項目使用的那些假*高級語言里,你想這麼寫也沒辦法)。
甚至,連這行的這個列表推導都可以繼續優化,比如用一些真*高級語言提供了的一些高階函數:
range(0, 5).map(${A+$, 100-10*$})
但這步優化是有帶商榷的,一方面,這麼寫後,對傳統程序員稍微友好了一點點,畢竟Java也在8版本引入了這些東西:
IntStream.range(0, 5).map(i -&> new AbstractMap.SimpleImmutableEntry(A + i, 100-10*i))
但另一方面,對數學又不那麼友好了,又不能直接的讀出,所以可讀性毫無疑問下降了很多。
最重要的是性能問題,這麼寫,實際在運行時增加了創建映射的開銷,畢竟不是硬編碼好的。雖然說對於真*高級語言,不是問題,因為可以在編譯階段完成宏展開,但對於Java這樣中不溜的就難辦了。可能你不得不自己搞些單例啊、靜態變數啊之類的來優化每次執行的創建開銷。
哦多,扯遠了,下面我們再看看例二的需求,怎麼Coding更好呢?
同樣,先建立數值與坐標軸的映射:
[(:ERROR, -30), (:WARNING, -20), (:nil, +30), (:WARNING, +40), (:ERROR, +INF)]
後面的一切還用我再說嘛。。。
最後,細心的童鞋可能會發現,以上代碼,除了那行Java的意外,居然 全 部 都 是 偽 代 碼!雖然不是教科書那種原始的機器偽代碼,但確實沒有一種語言能夠編譯通過。。。這意味著,好吧,只是「理想編碼」。實際編程實踐中,視所用語言,可能都不得不在某些地方做一些修改妥協。。。
最後的最後,給大家一點小建議,所謂見人說人話見鬼說鬼話,寫代碼也是這樣。什麼時候該寫什麼風格抽象到什麼程度,第一看其它參與者是碼農還是碼痴,第二看項目重業務還是邏輯,第三看語言偏工程還是玩具。
if ((test &> 1) (test &< 5))
{ alert();}無論邏輯簡單還是複雜,都大括弧換行,括弧加好,寧濫勿缺我覺得挺好的單行加不加括弧看在寫什麼,我習慣cpp/java/js就加,kotlin/c#這種不加
我只覺得C系列語言里,通常都要求把等值比較寫成
if(1==i){...}
這個比較反人類,很不喜歡,可是沒辦法,都要求這麼些寫,不這麼寫都不行。if(test&>1){}else if(test&<5){}else{}1.單從理解的角度來說,我覺著這樣更好理解。2.個人習慣,if語句只有一行也要用{}。
這樣寫是很方便閱讀呀。
難道不是看代碼給誰讀嗎
個人常用「自述式編程」(self-documenting code)的方法。
// JavaScript
const testIsBetweenOneAndFive = test &> 1 test &< 5; if (testIsBetweenOneAndFive) { // code }
這讓人可以以自然語言來明白你的「意圖」,如果需要,再去檢查你具體落實意圖的「做法」。閱讀代碼的時候 80% 的情況我們希望搞懂「這段代碼想表達什麼意思」,少數情況才需要追問「這段代碼怎麼表達它想要表達的意思」,用這種方式可以很好地解決前面那個問題。
當然題目中的例子並不是一個真正具備業務意義的意圖。更好的意圖可能是 userIsInfant 或者 ageIsInRange 之類的描述。
語言律師會告訴你 if ( isSuccess() ) 要寫成 if ( true == isSuccess() ) 這樣對讀代碼的人來說清晰明了 true寫前面還能防止漏寫等號 是不是很棒棒 我的觀點是 這都看不懂 明天就不用來了
謝邀
如果出現的情況少
而且邏輯沒有那麼複雜的話實際上怎樣都沒差糾結這點的時間都夠別人讀懂了如果邏輯比較複雜的應該把上下限和測量值計算好存入兩個變數這樣在條件中只有三個變數之間的關係也是比較好懂的如果經常出現判斷測量值是否在某個域中
應該對區域的概念進行封裝然後對這個封裝增加介面// 對於第一個例子
check(test).betweenNotEqual(1,5)// 對於第二個例子check(test).outOfNotEqual(-1,5)// 如果包含邊界check(test).betweenOrEqual(1,5)check(test).betweenOrEqualLeft(1,5)check(test).betweenOrEqualRight(1,5)check(test).outOfOrEqual(-1,5)check(test).outOfOrEqualLeft(-1,5)check(test).outOfOrEqualRight(-1,5)
╮( ̄▽ ̄)╭ 反正工程不是競賽
多封裝這一點點也不會扣分競賽不用考慮可持續發展24小時造一座橋過一輛車就行工程需要考慮持久提供服務24個月造一座橋持續運維24年直到新的交通方式出現後結束生命周期如果你總是為這些問題發愁,我建議你用python。
推薦閱讀:
※攀岩和編程有什麼共通點嗎?
※大力出奇蹟——Python暴力猜解Web應用
※C++學習第一課,之「Hello world」
※比特幣入門教程