Ref: Never-Mattt
本文是在閱讀Mattt作者后寫的。
Never一開始是用來取代Swift3之前的@noreturn
關(guān)鍵字的抄瓦。它本身只是一個enum呢诬,如果作為一個函數(shù)的返回值就代表這個函數(shù)永遠(yuǎn)不會返回,適用于一個函數(shù)需要不斷循環(huán)做一些事情,比如iOS的事件循環(huán)等育苟。
/// The return type of functions that do not return normally, that is, a type
/// with no values.
///
/// Use `Never` as the return type when declaring a closure, function, or
/// method that unconditionally throws an error, traps, or otherwise does
/// not terminate.
///
/// func crashAndBurn() -> Never {
/// fatalError("Something very, very bad happened")
/// }
public enum Never {
}
switch和Never
我們一般會把它作為函數(shù)的返回值(貌似也不怎么用到Never),其實(shí)也有一些其它用法椎木。巧妙地把Never用于傳參中會有意想不到的效果违柏。
Swift沒有一個標(biāo)準(zhǔn)的Result
類型,但大致和下面的描述差不多:
enum Result<Value, Error: Swift.Error> {
case success(Value)
case failure(Error)
}
Result
類型包含了values
和errors
香椎,一般用于異步的網(wǎng)絡(luò)請求中漱竖,例如:
func fetch(_ request: Request, completion: (Result<Response, Error>) -> Void) {
// ...
}
fetch(request) { result in
switch result {
case .success(let value):
print("Success: \(value)")
case .failure(let error):
print("Failure: \(error)")
}
}
現(xiàn)在,我們考慮這樣一種情況畜伐,一個函數(shù)在completion的handler里總是返回成功(success)的結(jié)果馍惹,也就沒必要寫failure
的case分支了,但是默認(rèn)情況下玛界,我們是需要寫failure
分支的⊥蚍現(xiàn)在我們利用Never可以做到不用寫它了:
func alwaysSucceeds(_ completion: (Result<String, Never>) -> Void) {
completion(.success("yes!"))
}
alwaysSucceeds { (result) in
switch result {
case .success(let string):
print(string)
}
}
要讓Nerve支持以上寫法,需要實(shí)現(xiàn)兩個協(xié)議:Swift.Error和Comparable慎框。
1.遵從Error協(xié)議良狈,使得Nerve能作為Result
類型的模板參數(shù)。
extension Never: Error {
// 剛好Error是一個空協(xié)議笨枯,不用再多寫什么
}
2.遵從Comparable協(xié)議薪丁,使得在對Result
對象做switch的時(shí)候可比較以跳轉(zhuǎn)正確的case分支。
extension Never: Comparable {
public static func < (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
public static func > (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
public static func == (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
}
Comparable協(xié)議只需要實(shí)現(xiàn)以上3個馅精,其它函數(shù)由編譯器自動補(bǔ)全严嗜。
完整代碼如下:
extension Never: Error {
}
extension Never: Comparable {
public static func < (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
public static func > (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
public static func == (lhs: Never, rhs: Never) -> Bool {
switch (lhs, rhs) {}
}
}
enum Result<Value, Error: Swift.Error> {
case success(Value)
case failure(Error)
}
func alwaysSucceeds(_ completion: (Result<String, Never>) -> Void) {
completion(.success("yes!"))
}
alwaysSucceeds { (result) in
switch result {
case .success(let string):
print(string)
}
}
但是個人覺得這種方式不如用if-case-let寫法來得直接:
if case .success(let value) = result {
// Do something
}
但從語義上來說switch-Nerve在閱讀上更加友好。
??運(yùn)算符和Nerve
??運(yùn)算符又叫空合并運(yùn)算符硫嘶。需要兩個操作數(shù)阻问,當(dāng)lhs為空的時(shí)候就使用rhs梧税。
強(qiáng)制解包(unwrap)運(yùn)算符(!)是一種危險(xiǎn)的操作沦疾,很容易引起程序崩潰。
let array: [Int] = []
let firstIem = array.first!
array為空第队,強(qiáng)制解包就會引起崩潰哮塞。
所以為了避免沒必要的崩潰,我們一般會用if-let or guard-let
去解包凳谦。
let array: [Int] = []
guard let firstItem = array.first else {
fatalError("array cannot be empty")
}
如果你知道為空的時(shí)候需要拋出異常忆畅,或者就是需要結(jié)束程序的時(shí)候,這樣寫就有點(diǎn)不太優(yōu)雅尸执。我們可以利用??和Never:
func ?? <T>(lhs: T?, rhs: @autoclosure () -> Never) -> T {
switch lhs {
case let value?:
return value
case nil:
rhs()
}
}
let firstItem = array.first ?? fatalError("array cannot be empty")
// Fatal error: array cannot be empty
當(dāng)然家凯,如果以后Never作為swift的基礎(chǔ)底層類型的時(shí)候缓醋,可能會自動支持作為??的rhs,就不需要我們?nèi)?shí)現(xiàn)func ??<T>(lhs: T?, rhs: @autoclosure () -> Never) -> T
原文還有兩個關(guān)于Never在未來使用的展望:throw
表達(dá)式和throws<Never>
標(biāo)記绊诲。不過我看來沒啥必要送粱,有興趣的朋友可以去原文看看。