原文: Emptiness
作者: Soroush Khanlou
譯者: kemchenj
假如 Swift 裡的 array 數組不能為空?
細心想想: 假如 Swift 曾經設計了非空的數組了. 但這會讓人很煩對吧? 什麼言語有非空的數組?
但是, Swift 比起 C 言語曾經修正了很多規則了. 例如, switch 裡不需求 break
了, 甚至可以運用 fallthrough
來把幾個 case 銜接起來. 沒有了 ++
操作符, 它是那麼的讓人迷惑, 多余, 並且沒了它言語會變得更好.
還有一點 Swift 跟 C 不一樣, Swift 需求顯式地聲明可空性. Swift 讓你運用 Optional
類型, 向類型零碎指定某個值能否能夠有空. 你可以說你有一個 controller, 或許能夠有一個 controller 也能夠沒有. 類型零碎可以在一切中央都反省一遍, 保證這個值在被需求運用時不會為空.
當 Optional
和 Array
發生交匯時, 你會有兩種方式去描繪空值: nil 或許是空數組.
這能夠會有點繞, 例如, 當你反省一個數組能否為 nil 或許為空數組的時分. 例如, 你想要更好地運用 Swift 裡的 optional chaining 的時分, optionalArray?.isEmpty
卻前往了一個 Optional
, 一個實質上很讓人迷惑的類型. 假如在 if
判別句裡運用了這一描繪的話, 編譯器會拋出一個編譯錯誤, 由於這是一個 Optional 的布爾值.
optionalArray == []
會被編譯, 但會在數組為 nil 的時分前往 false
, 而這並不是我們想要的行為. 你可以有這麼幾種方式到達目的, 但不多:
if optionalArray == nil || optionalArray == [] {
if let array = optionalArray, array.isEmpty {
if (optionalArray ?? []).isEmpty {
if optionalArray?.isEmpty != false {
if optionalArray?.isEmpty ?? false {
最復雜的辦法是記住不要運用 Optional 的數組. 我不斷嚴厲恪守著這個規則, 保證不會把不同類型的"空值"混合到一同. 關於別的"可空"類型我也是這麼做的 - 字典, 字符串, 布爾值和一些別的類型. 不得不去反省兩品種型的控制反省是我最不想做的事情.
恪守這個規則很容易, 例如說一個類裡的屬性, 但不能夠在一切狀況下都恪守這個規則. 例如, 從一個 Optional 的實例那裡獲取一個數組屬性就會成為一個 Optional 的數組.
let wheels = optionalCar?.wheels // 後果是 [Wheel]?
從一個字典外面去獲取數組也是一樣.
let wheels = dictionary["wheels"] as? [Wheel]
你不得不去在每一個語句前面都加上 ?? []
.
我們剛擺脫了無法分辨 controller 和可空 controller 的窘境. 取得了簡化語句, 增加錯誤和可聲明的才能. 如今卻又遇上了這種困境.
假如一個數組不能為空, 那 Optional 的數組就代表了空數組, 非 Optional 的數組則總會包括至多一個值. 就不能夠同時呈現兩種語義上的空值了, 而任何采用了別的語義的代碼都不會經過編譯.
Modeling非空數組關於樹立模型也很有用途. 通知類型零碎一個給定的數組永遠不能夠為空有時分很有用. 例如, 也許你的 User
類有許多個郵箱, 但假如 user 沒有郵箱的話則不應該被驗證. 可以讓類型零碎接納這樣的描繪是一件很棒的時期, 但如今我們做不到. 其他例子:
一個 Country
國度必需有至多一座 City
城市.
一張 Album
專輯必需有至多一首 Song
歌.
一棟 Building
樓必需有至多一層 Floor
.
這樣的例子一大堆.
假如一個數組類型不能為空, 這些關系和約束全部都可以在類型零碎裡展示出來, 並且你不能刪掉數組裡的最後一個元素.
Expressions 語句表述隨著 Optional
類型的呈現, 許多表述都被簡化 當你知道一個類型永遠不能夠為空的時分, 你可以跳過空值反省, 用一個更直觀的方式去操作它. 關於非空的數組也是一樣的. 如今, Collection
協議的辦法, 例如 first
, last
, max
和 min
都會前往 Optional
, 只是為了處置數組為空的狀況.
有許多的狀況下數組都不會為空, 但每當我運用諸如 first
之類的辦法的時分, 我還是不得不去做進攻, 僅僅只是為了通知類型零碎它不為空.
假如數組不能夠為空的話, 這些辦法都可以前往一個非空值, 運用這些語句都會變得更容易. 空數組可以經過 optional chaining 來調用這些辦法, 而前往值也會是 Optional
.
假如數組不能夠為空, 那往非空數組裡拔出內容就可以很正常地任務. 但往一個可空數組裡拔出值就會是一場災難.
var emptiableArray = //...
emptiableArray == nil
? emptiableArray = [newItem]
: emptiableArray?.append(newItem)
這很讓人心煩, 但好音訊是, 在 Swift 3.1 裡, 我們可以給特定類型的泛型類型添加 extension. 那麼, 我們就可以往 Optional
的 Array
類型添加辦法(在這之前, 你只能給運用了恪守了協議的某個類型添加 extension)
extension Optional> {
func append(_ element: Element) {
switch self {
case .some(array):
array.append(element)
case .none:
self = [element]
}
}
}
如今我們可以像之前那樣疏通無阻的操作了.
Without Loss Of Generality我們再進一步, 假如數組的泛型參數包括了數組長度呢? 例如, 給 Array
拔出一個值的時分就會前往一個 Array
雖然這些東西十分好玩, 但也有一點不實在際. 你想想, 這意味著你不能在類裡保管數組了, 除非你知道這個數組的長度永遠不會被改動. 在很多狀況下, 你不能夠知道編譯時會有多少個對象從 API 和數據庫裡被前往
復雜的鑒別 空/非空 有很明白的理想意義, 並且也會簡化 Swift 很多外部運作方式.
NonEmptyArrayThis blog post is mostly a thought experiment. But it’s also a regular experiment. To that end, I built a non-empty array type. You can find it on GitHub here. It acts just like an array, but it isn’t emptiable. It conforms to Sequence
, Collection
, and has ==
and !=
methods.
這篇文章更像是一個 Idea 的嘗試. 但這也只是一個慣例嘗試. 作為開頭, 我樹立了一個非空數組類型. 你可以到這裡看源碼, 運作起來好像一個數組, 但不為空. 恪守 Sequence
, Collection
協議並且有 ==
和 !=
辦法.
由於 Swift 的類型零碎有一局部我沒能完全了解, 但雖然如此, 你還是可以重寫協議(例如 Collection
)裡的辦法(例如 first
), 然後把 Element?
修正了 Element
, Swift 會在調用時爭產任務, 並且運用愈加明白的類型, Element
. 這意味著 NonEmptyArray
會在 first
, last
, max
和 min
裡前往 non-optional, 雖然 Collection
裡它們被定義為 Optional
, repo 裡的測試有斷言來判別這個.
擁有一個相對不為空的數組會有很多風趣的事情發作. 拔出還好, 但刪除元素的辦法會帶來更多問題. 我把這個辦法標志為 throws
, 但經過更多考慮之後, 這也許不是一種正確地做法. 畢竟, Swift 原生的數組刪除元素時也會發生問題, 只是它比起 NonEmptyArray
可以一個以上的元素. Swift 的數組會在嘗試刪除空數組的元素時調用 fatalError
, 所以也許這才是正確地做法.
我很等待可以把 NonEmptyArray
拆分紅幾個提案, 看看得到 Swift 原生數組類型的語法糖能否值得, 去換取前往 non-optional 的辦法.
以上就是對Emptiness 空值語義的相關引見,希望對您學習IOS有所協助,感激您關注本站!
【Emptiness 空值語義】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!