做者:Soroush Khanlou,原文連接,原文日期:2016-06-21
譯者:Crystal Sun;校對:千葉知風;定稿:CMBpython
在 Python 中,零和 None
,以及空列表、字典和字符串,都有 falsy 值。 若是有 falsy 值,意味着能夠它在 if 語句中使用,且可使用 else。 例如,在 Python 中:git
python if []: # will not be evaluated else: # will be evaluated if 0: # will not be evaluated else: # will be evaluated
而在 Swift 中,只有真正的布爾值才能夠用在 if 語句裏。 nil、空數組,或者其餘類型的值出如今在 if 語句中會致使編譯失敗:github
if Array<String>() { // error: type 'Array<String>' does not conform to protocol 'BooleanType'
Python 和 Swift 都具備一致性,這是好事。在 Swift 裏,只有布爾值能夠做爲 if 語句的判斷條件。而在 Python 中,每一個集合類型、整數、nil 值(None
)和布爾均可以做爲 if 語句的判斷條件。一致性看起來彷佛簡單,直到你注意到其餘語言有多糟糕。swift
JavaScript 纔是真正的垃圾秀。 false
、null
和 undefined
是 falsy,這或多或少還能忍受。可是 0
和 「」
也是 falsy,即便 []
和 {}
是 truthy。 (還有不要嘗試解釋 JavaScript 的相等行爲。數組
雖然我很愛 Objective-C,但它仍然是不具備一致性的語言。 nil
,NO
,false
和 0
是 falsy,而 @ []
,@ {}
,@ 0
和 @NO
是 truthy。 Ruby 在這方面是最好的,只容許 nil
和 false
是 falsy。比起 Ruby,我更喜歡 Swift 的絕對嚴格。app
一致性雖好,但效用更重要。Swift 的 falsiness 規則雖然好,不過仍是 Python 的規則實用。this
我有兩個證據能夠證實,爲何 Python 的規則比 Swift 的(以及幾乎全部其餘語言的)更實用。lua
第一個證據是 Rails 的 ActiveSupport
裏的 present?
方法。我以前寫過 present?
的方法,見這裏 。簡而言之,可規避 Ruby 運行時惟一不可變的 falsiness。每一個對象均可以規定若是 #present?
.nil
不存在,包括空數組和字符串。能夠給對象重寫 present?
,若是有自定義集合或空對象。這樣會致使你的代碼這樣:翻譯
if myObject.present? { } else { }
重寫 Ruby 頑固的 falsiness。 ActiveSupport 只是單純有用,這也是爲何調用 .present?
(和 .blank?
)老是散佈在 Rails 的代碼庫裏。code
第二個證據是,Swift 在條件句中處理可選值時是多麼尷尬。 留意一下想在代碼中檢查一個東西是 empty 仍是 nil ,得進行多少操做。而這種檢查對我而言很是常見。例如,UITextField 的 text 屬性是可選的,若是想檢查 text 是否存在,就要進行相似尷尬的操做了:
if let text = textField.text where !text.isEmpty { // we have some text } else { // the string is either empty or nil }
若是這樣的代碼都讓你不以爲尷尬,那來嘗試顛倒條件。 我會等你噠。 (提示:不能只刪除 not 運算符)
很快,你會專門爲字符串添加 Optional
方法:
protocol TextContaining { var isEmpty: Bool { get} } extension String: TextContaining { } extension Optional where Wrapped: TextContaining { var isEmpty: Bool { switch self { case let .Some(value): return value.isEmpty case .None: return true } } }
你沒必要這樣生活! 你值得擁有美好的事情!(好比 Python 的 falsiness)。
不像我提到的其餘語言,Swift 是一個高度動態的語言。 容許添加代碼來更改編譯器的 falsiness 行爲。
這是 BooleanType
的文檔:
符合布爾型協議的類型能夠用於條件語句(if,while,C-style for)和其餘邏輯值上下文(例如,guard 語句)。
是的的的的的。
Swift 只有三個類型符合 BooleanType 類型, Bool,DarwinBoolean和ObjCBool。 不建議將此集合擴展爲包含表示多個簡單布爾值的類型。
Swift 只有三個類型符合 BooleanType 類型, Bool,DarwinBoolean和ObjCBool。 不建議將此集合擴展爲包含表示多個簡單布爾值的類型。
對不起,Chris Lattner,我要放手一搏了:
extension String: BooleanType { public var boolValue: Bool { return !self.isEmpty } }
完成了!如今咱們能夠在條件語句中使用字符串了,代碼如期編譯成功:
if "" { // this code will not be executed } else { // this code will be executed }
能夠對 Dictionary
和 Array
作一樣的事情。對可選值來講,咱們應該檢查一下 Wrapped
類型是否遵循 BooleanType
:
extension Optional: BooleanType { public var boolValue: Bool { switch self { case .None: return false case .Some(let wrapped): if let booleanable = wrapped as? BooleanType { return booleanable.boolValue } return true } } }
如今,若是有個拆包的布爾值,實現效果會如你所願,不會拋出編譯報錯,不須要在處理奇怪的 optionalBool ?? true
了。
最大的問題是「我應該在生產代碼中這樣作嗎?」。答案是...也許能夠吧。若是你在寫一個開源庫,可能被其餘的開發者使用,那絕對不要這樣作。若是是在本身寫的 App 裏添加這樣的代碼,那不要牽扯任何第三方代碼,否則會編譯不過的。Swift 是強類型的語言,甚至沒法編譯 myArray == false
這樣的代碼。
我以爲 Swift 這樣作很是棒:建構在一個個小的可組合的塊(好比 BooleanType)上,標準庫能夠在語言中進行自定義(像是 ArrayLiteralConvention 這樣的類型都遵循類似的模式)。使人驚訝的是,沒有一個「動態」語言容許這種基本語言結構的突變。同時,我不得不決定是否要在全部的地方進行這樣的嘗試。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。