為什麼第三種寫法不對呢?


Swift 3.0 中,a++ 被廢除,print(a++) 這條代碼已經不合法,而 print( a += 1) 反而是合法的語句。

a += 1 是 a = a + 1 的簡寫,是賦值語句。賦值語句沒有返回值,或者說它的返回值是 ()。Swift 支持多返回值,當返回多個值時寫成 (a, b, c); 只有一個值時,寫成 a, 相當於 (a); 等沒有返回值時,就相當於 ()。

print( a += 1) 相當於 print( a = a + 1),相當於

a = a + 1
print(())

最終列印出 ()。

----------------------

Swift 從語法設計上杜絕了一些 Objective-C 的坑,這些坑是從 C 語言延續過來的。

假如賦值語句有返回值。就可能將

if (a == 1) {
}

錯誤寫成

if (a = 1) {
}

在 C 語言中,為避免不小心寫錯,有時會寫成

if (1 == a) {
}

這種寫法被稱為 Yoda 表達式,因為《星球大戰》中的 Yoda 大師喜歡使用這樣奇特的倒裝句子。

Swift 語法上要求 if、while 後面判斷式子一定需要傳入布爾類型,並且賦值沒有返回值。寫成 if a = 1 就會編譯錯誤。Yoda 表達式這種變通寫法就沒有必要了。

Swift 3.0 中,去掉 a++,就不用再費神區分 a++ 和 ++a 的區別。也就不會出現 ++++a++++ 等於多少的無聊問題。

---------------------------

有些人或者覺得 if 中的語句是 Bool 類型,就已經解決了 if a = 1 的問題,賦值沒有返回值是不是太過分呢。但賦值就是賦值,本來就不應該有返回值。就算 if 中的語句強制是 Bool 類型,假如賦值有返回值,還是可以寫類似的坑人代碼。

if (x = y) &> 0 {
}

而假如 x 和 y 都是 Bool 值,也就可以寫成

if (x = y) {
}

另外還有

if x += 1 &> 0 {
}

甚至是

doSomething(x = y, y = z, z = x)

幸好在 Swift 中,這些代碼都不會再出現。有可能會犯的錯誤就一定有人會犯,就算犯過的人吸取了經驗不再犯了,還是會有源源不斷的新人會犯同樣的錯誤。靠 IDE 的 warning 是不管用的。

那賦值沒有返回值,會犧牲了什麼呢?只不過是將一行含糊的代碼拆兩行更確定的代碼。有些人可能會覺得這樣就不夠簡潔,但是在程序當中,簡潔並非指字元越少越好的。

這個問題,王垠寫過文章討論過。程序語言的常見設計錯誤(1) - 片面追求短小, 雖然他很多文章比較極端,但這篇文章我是認同的。


看函數+=聲明,沒有返回值,大部分人直覺都會認為是這個原因。真相可能是:恭喜你,找到了一個bug

因為Void是默認返回值; +=實際上相當於:

public func +=(lhs: inout Int, rhs: Int) -&> Void

因為Void是typealias, a+=1的結果相當於 Void() ,而不是Void.

print(a+=1) 就相當於 print(Void())

在xcode7.1中

print(Void()) //成功
print(a+=1) //出錯

我相信是因為Swift的未完善,而導致的Xcode的bug。不過好在Xcode升級到8.1後,官方已經解決。

類似的bug,print(Void)在Xcode8.1中不再支持(因為是typealias,說白了是Type )必須這樣:

//Xcode8.1
print(Void.self) //列印Type
print(Void()) //列印Value


其實解決條件表達式里 == 誤寫成 = 的方法就是要求條件的類型必須為 bool,這樣能篩掉大部分的錯誤。另外都2016年了這個老生常談的問題應該不會有太多人犯了,智能的 IDE 也基本會報 warning。放棄 a += 1 可以做 rvalue 的設計,有多少簡潔的代碼要分好多行,或者多定義幾個完全不必要的臨時變數來記錄中間值啊。

有點像當年 @Nullable Annotation 沒有引入的時候,一堆 Java 程序員發明了

"A string literal".equals(fooVariable)

這種丑到爆的寫法,並號稱這樣的寫法能避免 fooVariable 是 null 的時候可能導致的 NullPointerException。一臉懵逼。你自己寫一個函數,裡邊用到的每個變數能不能是 null 你還不知道?寫成

fooVariable.equals("A string literal")

就是為了讓錯誤在更早的地方暴露出來,這樣修 BUG、分鍋的時候都有個依據。不然你按照前一種寫法湊合著跑下去了,然後把結果交給別的函數,別的函數里再出個別的錯誤,連錯誤地方都很難定位。

Swift 引入 Optional 的概念就是強製程序員時刻想清楚變數會不會是 null。

關於 null 為什麼是 Java 里最糟糕的設計之一,有很多文章都已經做了詳細的分析。如果想避免類似的問題的話,請使用基於 Apache License 2.0 的 Guava 里的 Optional& 和 Preconditions 來做必要的變數檢查。


為什麼不更新一下 Xcode 呢?


a+=1等於a=a+1

這個不能放在括弧里當參數用吧。

你可以寫在外面當變數。


推薦閱讀:

VS會不會成為移動開發首選?C#會不會崛起?
舊的 iOS 應用該如何適配 iOS 7?
App 的頻繁升級,會讓你覺得厭煩嗎?
在Unity3D的Asset Store中賣插件有什麼值得分享的經驗?
零基礎初學者如何學習製作APP?

TAG:iOS開發 | Swift語言 | Swift編程 |