欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift設(shè)計(jì)思想Result<T>與Result<T,?E:?Error>類型解析

 更新時(shí)間:2022年11月30日 09:13:49   作者:王巍  
這篇文章主要為大家介紹了Swift設(shè)計(jì)思想Result<T>與Result<T,?E:?Error>的類型示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景知識(shí)

Cocoa API 中有很多接受回調(diào)的異步方法,比如 URLSession 的 dataTask(with:completionHandler:)。

URLSession.shared.dataTask(with: request) {
    data, response, error in
        if error != nil {
            handle(error: error!)
        } else {
            handle(data: data!)
        }
}

有些情況下,回調(diào)方法接受的參數(shù)比較復(fù)雜,比如這里有三個(gè)參數(shù):(Data?, URLResponse?, Error?),它們都是可選值。當(dāng) session 請(qǐng)求成功時(shí),Data 參數(shù)包含 response 中的數(shù)據(jù),Error 為 nil;當(dāng)發(fā)生錯(cuò)誤時(shí),則正好相反,Error 指明具體的錯(cuò)誤 (由于歷史原因,它會(huì)是一個(gè) NSError 對(duì)象),Data 為 nil。

關(guān)于這個(gè)事實(shí),dataTask(with:completionHandler:) 的文檔的 Discussion 部分有十分詳細(xì)的說明。另外,response: URLResponse? 相對(duì)復(fù)雜一些:不論是請(qǐng)求成功還是失敗,只要從 server 收到了 response,它就會(huì)被包含在這個(gè)變量里。

這么做雖然看上去無害,但其實(shí)存在改善的余地。顯然 data 和 error 是互斥的:事實(shí)上是不可能存在 data 和 error 同時(shí)為 nil 或者同時(shí)非 nil 的情況的,但是編譯器卻無法靜態(tài)地確認(rèn)這個(gè)事實(shí)。編譯器沒有制止我們?cè)阱e(cuò)誤的 if 語句中對(duì) nil 值進(jìn)行解包,而這種行為將導(dǎo)致運(yùn)行時(shí)的意外崩潰。

我們可以通過一個(gè)簡單的封裝來改進(jìn)這個(gè)設(shè)計(jì):如果你實(shí)際寫過 Swift,可能已經(jīng)對(duì) Result 很熟悉了。它的思想非常簡單,用泛型將可能的返回值包裝起來,因?yàn)榻Y(jié)果是成功或者失敗二選一,所以我們可以藉此去除不必要的可選值。

enum Result<T, E: Error> {
    case success(T)
    case failure(E)
}

把它運(yùn)用到 URLSession 中的話,包裝一下 URLSession 方法,上面調(diào)用可以變?yōu)椋?/p>

// 如果 Result 存在于標(biāo)準(zhǔn)庫的話,
// 這部分代碼應(yīng)該由標(biāo)準(zhǔn)庫的 Foundataion 擴(kuò)展進(jìn)行實(shí)現(xiàn)
extension URLSession {
    func dataTask(with request: URLRequest, completionHandler: @escaping (Result<(Data, URLResponse), NSError>) -> Void) -> URLSessionDataTask {
        return dataTask(with: request) { data, response, error in
            if error != nil {
                completionHandler(.failure(error! as NSError))
            } else {
                completionHandler(.success((data!, response!)))
            }
        }
    }
}
URLSession.shared.dataTask(with: request) { result in
    switch result {
    case .success(let (data, _)):
        handle(data: data)
    case .failure(let error):
        handle(error: error)
    }
}

這里原文代碼中 completionHandler 里 (Result<(Data, URLResponse), NSError>) -> Void) 這個(gè)類型是錯(cuò)誤的。Data 存在時(shí) URLResponse 一定存在,但是我們上面討論過,當(dāng) NSError 不為 nil 時(shí),URLResponse 也可能存在。原文代碼忽略了這個(gè)事實(shí),將導(dǎo)致 error 狀況時(shí)無法獲取到可能的 URLResponse。正確的類型應(yīng)該是 (Result<(Data), NSError>, URLResponse?) -> Void

當(dāng)然,在回調(diào)中對(duì) result 的處理也需要對(duì)應(yīng)進(jìn)行修改。

調(diào)用的時(shí)候看起來很棒,我們可以避免檢查可選值的情況,讓編譯器保證在對(duì)應(yīng)的 case 分支中有確定的非可選值。這個(gè)設(shè)計(jì)在很多存在異步代碼的框架中被廣泛使用,比如 Swift Package Manager,Alamofire 等中都可覓其蹤。

上面代碼注釋中提到,「如果 Result 存在于標(biāo)準(zhǔn)庫的話,這部分代碼應(yīng)該由標(biāo)準(zhǔn)庫的 Foundataion 擴(kuò)展進(jìn)行實(shí)現(xiàn)」。但是考慮到原有的可選值參數(shù) ((Data?, URLResponse?, Error?)) 作為回調(diào)的 API 將會(huì)共享同樣的函數(shù)名,所以上面的函數(shù)命名是不可取的,否則將導(dǎo)致沖突。在這類 public API 發(fā)布后,如何改善和迭代確實(shí)是個(gè)難題。一個(gè)可行的方法是把 Foundation 的 URLSession deprecate 掉,提取出相關(guān)方法放到諸如 Network.framework 里,并讓它跨平臺(tái)。另一種可行方案是通過自動(dòng)轉(zhuǎn)換工具,強(qiáng)制 Swift 使用 Result 的回調(diào),并保持 OC 中的多參數(shù)回調(diào)。如果你正在打算使用 Result 改善現(xiàn)有設(shè)計(jì),并且需要考慮保持 API 的兼容性時(shí),這會(huì)是一個(gè)不小的挑戰(zhàn)。

錯(cuò)誤類型泛型參數(shù)

如此常用的一個(gè)可以改善設(shè)計(jì)的定義,為什么沒有存在于標(biāo)準(zhǔn)庫中呢?關(guān)于 Result,其實(shí)已經(jīng)有相關(guān)的提案

這個(gè)提案中值得注意的地方在于,Result 的泛型類型只對(duì)成功時(shí)的值進(jìn)行了類型約束,而忽略了錯(cuò)誤類型。給出的 Result 定義類似這樣:

enum Result<T> {
    case success(T)
    case failure(Error)
}

很快,在 1 樓就有人質(zhì)疑,問這樣做的意義何在,因?yàn)楫吘购芏嘁汛嬖诘?nbsp;Result 實(shí)現(xiàn)都是包含了 Error 類型約束的。確定的 Error 類型也讓人在使用時(shí)多了一份“安全感”。

不過,其實(shí)我們實(shí)際類比一下 Swift 中已經(jīng)存在的錯(cuò)誤處理的設(shè)計(jì)。Swift 中的 Error 只是一個(gè)協(xié)議,在 throw 的時(shí)候,我們也并不會(huì)指明需要拋出的錯(cuò)誤的類型:

func methodCanThrow() throws {
    if somethingGoesWrong {
        // 在這里可以 throw 任意類型的 Error
    }
}
do {
    try methodCanThrow()
} catch {
    if error is SomeErrorType {
        // ...
    } else if error is AnotherErrorType {
        // ...
    }
}

但是,在帶有錯(cuò)誤類型約束的 Result<T, E: Error> 中,我們需要為 E 指定一個(gè)確定的錯(cuò)誤類型 (或者說,Swift 并不支持在特化時(shí)使用協(xié)議,Result<Response, Error> 這樣的類型是非法的)。這與現(xiàn)有的 Swift 錯(cuò)誤處理機(jī)制是背道而馳的。

關(guān)于 Swift 是否應(yīng)該拋出帶有類型的錯(cuò)誤,曾經(jīng)存在過一段時(shí)間的爭論。最終問題歸結(jié)于,如果一個(gè)函數(shù)可以拋出多種錯(cuò)誤 (不論是該函數(shù)自身產(chǎn)生的錯(cuò)誤,還是在函數(shù)中 try 其他函數(shù)時(shí)它們所帶來的更底層的錯(cuò)誤),那么 throws 語法將會(huì)變得非常復(fù)雜且不可控 (試想極端情況下某個(gè)函數(shù)可能會(huì)拋出數(shù)十種錯(cuò)誤)?,F(xiàn)在大家一致的看法是已有的用 protocol Error 來定義錯(cuò)誤的做法是可取的,而且這也編碼在了語言層級(jí),我們對(duì)「依賴編譯器來確定 try catch 會(huì)得到具體哪種錯(cuò)誤」這件事,幾乎無能為力。

另外,半開玩笑地說,要是 Swift 能類似這樣 extension Swift.Error: Swift.Error {},支持協(xié)議遵守自身協(xié)議的話,一切就很完美了,XD。

選擇哪個(gè)比較好?

兩種方式各有優(yōu)缺點(diǎn),特別在如果需要考慮 Cocoa 兼容的情況下,更并說不上哪一個(gè)就是完勝。這里將兩種寫法的優(yōu)缺點(diǎn)簡單比較一下,在實(shí)踐中最好是根據(jù)項(xiàng)目情況進(jìn)行選擇。

Result<T, E: Error>

優(yōu)點(diǎn)

可以由編譯器幫助進(jìn)行確定錯(cuò)誤類型

當(dāng)通過使用某個(gè)具體的錯(cuò)誤類型擴(kuò)展 Error 并將它設(shè)定為 Result 的錯(cuò)誤類型約束后,在判斷錯(cuò)誤時(shí)我們就可以比較容易地檢查錯(cuò)誤處理的完備情況了:

 enum UserRegisterError: Error {
     case duplicatedUsername
     case unsafePassword
 }
 userService.register("user", "password") {
     result: Result<User, UserRegisterError> in
     switch result {
     case .success(let user):
         print("User registered: \(user)")
     case .failure(let error):
         if error == .duplicatedUsername {
             // ...
         } else if error == .unsafePassword {
             // ...
         }
     }
 }

上例中,由于 Error 的類型已經(jīng)可以被確定是 UserRegisterError,因此在 failure 分支中的檢查變得相對(duì)容易。

這種編譯器的類型保證給了 API 使用者相當(dāng)強(qiáng)的信心,來從容進(jìn)行錯(cuò)誤處理。如果只是一個(gè)單純的 Error 類型,API 的用戶將面臨相當(dāng)大的壓力,因?yàn)椴环單臋n的話,就無從知曉需要處理怎樣的錯(cuò)誤,而更多的情況會(huì)是文檔和事實(shí)不匹配…

但是帶有類型的錯(cuò)誤就相當(dāng)容易了,查看該類型的 public member 就能知道會(huì)面臨的情況了。在制作和發(fā)布框架,以及提供給他人使用的 API 的時(shí)候,這一點(diǎn)非常重要。

按條件的協(xié)議擴(kuò)展

使用泛型約束的另一個(gè)好處是可以方便地對(duì)某些情況的 Result 進(jìn)行擴(kuò)展。

舉例來說,某些異步操作可能永遠(yuǎn)不會(huì)失敗,對(duì)于這些操作,我們沒有必要再使用 switch 去檢查分支情況。一個(gè)很好的例子就是 Timer,我們?cè)O(shè)定一個(gè)在一段時(shí)間后執(zhí)行的 Timer 后,如果不考慮人為取消,這個(gè) Timer 總是可以正確執(zhí)行完畢,而不會(huì)發(fā)生任何錯(cuò)誤的。我們可能會(huì)選擇使用一個(gè)特定的類型來代表這種情況:

 enum NoError: Error {}
 func run(after: TimeInterval, done: @escaping (Result<Timer, NoError>) -> Void ) {
     Timer.scheduledTimer(withTimeInterval: after, repeats: false) { timer in
         done(.success(timer))
     }
 }

在使用的時(shí)候,本來我們需要這樣的代碼:

 run(after: 2) { result in
     switch result {
     case .success(let timer):
         print(timer)
     case .failure:
         fatalError("Never happen")
     }
 }

但是,通過對(duì) E 為 NoError 的情況添加擴(kuò)展,可以讓事情簡單不少:

 extension Result where E == NoError {
     var value: T {
         if case .success(let v) = self {
             return v
         }
         fatalError("Never happen")
     }
 }
 run(after: 2) {
     // $0.value is the timer object
     print($0.value)
 }

這個(gè) Timer 的例子雖然很簡單,但是可能實(shí)際上意義不大,因?yàn)槲覀兛梢灾苯邮褂?nbsp;Timer.scheduledTimer 并使用簡單的 block 完成。但是當(dāng)回調(diào) block 有多個(gè)參數(shù)時(shí),或者需要鏈?zhǔn)秸{(diào)用 (比如為 Result 添加 map,filter 之類的支持時(shí)),類似 NoError 這樣的擴(kuò)展方式就會(huì)很有用。

在 NSHipster 里有一篇關(guān)于 Never 的文章,提到使用 Never 來代表無值的方式。其中就給出了一個(gè)和 Result 一起使用的例子。我們只需要使 extension Never: Error {} 就可以將它指定為 Result<T, E: Error> 的第二個(gè)類型參數(shù),從而去除掉代碼中對(duì) .failure case 的判斷。這是比 NoError 更好的一種方式。

當(dāng)然,如果你需要一個(gè)只會(huì)失敗不會(huì)成功的 Result 的話,也可以將 Never 放到第一個(gè)類型參數(shù)的位置:Result<Never, E: Error>。

缺點(diǎn)

與 Cocoa 兼容不良

由于歷史原因,Cocoa API 中表達(dá)的錯(cuò)誤都是”無類型“的 NSError 的。如果你跳出 Swift 標(biāo)準(zhǔn)庫,要去使用 Cocoa 的方法 (對(duì)于在 Apple 平臺(tái)開發(fā)來說,這簡直是一定的),就不得不面臨這個(gè)問題。很多時(shí)候,你可能會(huì)被寫成 Result<SomeValue, NSError> 的形式,這樣我們上面提到的優(yōu)點(diǎn)幾乎就喪失殆盡了。

可能需要多層嵌套或者封裝

即使對(duì)于限定在 Swift 標(biāo)準(zhǔn)庫的情況來說,也有可能存在某個(gè) API 產(chǎn)生若干種不同的錯(cuò)誤的情況。如果想要完整地按照類型處理這些情況,我們可能會(huì)需要將錯(cuò)誤嵌套起來:

 // 用戶注冊(cè)可能產(chǎn)生的錯(cuò)誤
 // 當(dāng)用戶注冊(cè)的請(qǐng)求完成且返回有效數(shù)據(jù),但數(shù)據(jù)表明注冊(cè)失敗時(shí)觸發(fā)
 enum UserRegisterError: Error {
     case duplicatedUsername
     case unsafePassword
 }
 // Server API 整體可能產(chǎn)生的錯(cuò)誤
 // 當(dāng)請(qǐng)求成功但 response status code 不是 200 時(shí)觸發(fā)
 enum APIResponseError: Error {
     case permissionDenied // 403
     case entryNotFound    // 404
     case serverDied       // 500
 }
 // 所有的 API Client 可能發(fā)生的錯(cuò)誤
 enum APIClientError: Error {
     // 沒有得到響應(yīng)
     case requestTimeout
     // 得到了響應(yīng),但是 HTTP Status Code 非 200
     case apiFailed(APIResponseError)
     // 得到了響應(yīng)且為 200,但數(shù)據(jù)無法解析為期望數(shù)據(jù)
     case invalidResponse(Data)
     // 請(qǐng)求和響應(yīng)一切正常,但 API 的結(jié)果是失敗 (比如注冊(cè)不成功)
     case apiResultFailed(Error)
 }

上面的錯(cuò)誤嵌套比較幼稚。更好的類型結(jié)構(gòu)是將 UserRegisterError 和 APIResponseError 定義到 APIClientError 里,另外,因?yàn)椴粫?huì)直接拋出,因此沒有必要讓 UserRegisterError 和 APIResponseError 遵守 Error 協(xié)議,它們只需要承擔(dān)說明錯(cuò)誤原因的任務(wù)即可。

對(duì)這幾個(gè)類型加以整理,并重新命名,現(xiàn)在我認(rèn)為比較合理的錯(cuò)誤定義如下 (為了簡短一些,我去除了注釋):

enum APIClientError: Error {
    enum ResponseErrorReason {
        case permissionDenied
        case entryNotFound
        case serverDied
    }
    enum ResultErrorReason {
        enum UserRegisterError {
            case duplicatedUsername
            case unsafePassword
        }
        case userRegisterError(UserRegisterError)
    }
    case requestTimeout
    case apiFailed(ResponseErrorReason)
    case invalidResponse(Data)
    case apiResultFailed(ResultErrorReason)
}

當(dāng)然,如果隨著嵌套過深而縮進(jìn)變多時(shí),你也可以把內(nèi)嵌的 Reason enum 放到 APIClientError 的 extension 里去。

上面的 APIClientError 涵蓋了進(jìn)行一次 API 請(qǐng)求時(shí)所有可能的錯(cuò)誤,但是這套方式在使用時(shí)會(huì)很痛苦:

 API.send(request) { result in
     switch result {
     case .success(let response): //...
     case .failure(let error):
         switch error {
         case .requestTimeout: print("Timeout!")
         case .apiFailed(let apiFailedError):
             switch apiFailedError: {
                 case .permissionDenied: print("403")
                 case .entryNotFound: print("404")
                 case .serverDied: print("500")
             }
         case .invalidResponse(let data):
             print("Invalid response body data: \(data)")
         case .apiResultFailed(let apiResultError):
             if let apiResultError = apiResultError as? UserRegisterError {
                 switch apiResultError {
                     case .duplicatedUsername: print("User already exists.")
                     case .unsafePassword: print("Password too simple.")
                 }
             }
         }
     }
 }

相信我,你不會(huì)想要寫這種代碼的。

經(jīng)過半年的實(shí)踐,事實(shí)是我發(fā)現(xiàn)這樣的代碼并沒有想象中的麻煩,而它帶來的好處遠(yuǎn)遠(yuǎn)超過所造成的不便。

這里代碼中有唯一一個(gè) as? 對(duì) UserRegisterError 的轉(zhuǎn)換,如果采用更上面引用中定義的 ResultErrorReason,則可以去除這個(gè)類型轉(zhuǎn)換,而使類型系統(tǒng)覆蓋到整個(gè)錯(cuò)誤處理中。

相較于對(duì)每個(gè) API 都寫這樣一堆錯(cuò)誤處理的代碼,我們顯然更傾向于集中在一個(gè)地方處理這些錯(cuò)誤,這在某種程度上“強(qiáng)迫”我們思考如何將錯(cuò)誤處理的代碼抽象化和一般化,對(duì)于減少冗余和改善設(shè)計(jì)是有好處的。另外,在設(shè)計(jì) API 時(shí),我們可以提供一系列的便捷方法,來讓 API 的用戶能很快定位到某幾個(gè)特定的感興趣的錯(cuò)誤,并作出處理。比如:

extension APIClientError {
    var isLoginRequired: Bool {
        if case .apiFailed(.permissionDenied) = self {
            return true
        }
        return false
    }
}

用 error.isLoginRequired 即可迅速確定是否是由于用戶權(quán)限不足,需要登錄,產(chǎn)生的錯(cuò)誤。這部分內(nèi)容可以由 API 的提供者主動(dòng)定義 (這樣做也起到一種指導(dǎo)作用,來告訴 API 用戶到底哪些錯(cuò)誤是特別值得關(guān)心的),也可以由使用者在之后自行進(jìn)行擴(kuò)展。

另一種”方便“的做法是使用像是 AnyError 的類型來對(duì) Error 提供封裝:

 struct AnyError: Error {
     let error: Error
 }

這可以把任意 Error 封裝并作為 Result<Value, AnyError> 的 .failure 成員進(jìn)行使用。但是這時(shí) Result<T, E: Error> 中的 E 幾乎就沒有意義了。

Swift 中存在不少 Any 開頭的類型,比如 AnyIterator,AnyCollectionAnyIndex 等等。這些類型起到的作用是類型抹消,有它們存在的歷史原因,但是隨著 Swift 的發(fā)展,特別是加入了 Conditional Conformance 以后,這一系列 Any 類型存在的意義就變小了。

使用 AnyError 來進(jìn)行封裝 (或者說對(duì)具體 Error 類型進(jìn)行抹消),可以讓我們拋出任意類型的錯(cuò)誤。這更多的是一種對(duì)現(xiàn)有 Cocoa API 的妥協(xié)。對(duì)于純 Swift 環(huán)境來說,AnyError 并不是理想中應(yīng)該存在的類型。因此如果你選擇了 Result<T, E: Error> 的話,我們就應(yīng)該盡可能避免拋出這種無類型的錯(cuò)誤。

那問題就回到了,對(duì)于 Cocoa API 拋出的錯(cuò)誤 (也就是以前的 NSError),我們應(yīng)該怎樣處理?一種方式是按照文檔進(jìn)行封裝,比如將所有 NSURLSessionError 歸類到一個(gè) URLSessionErrorReason,然后把從 Cocoa 得到的 NSError 作為關(guān)聯(lián)值傳遞給使用者;另一種方式是在拋出給 API 使用者之前,在內(nèi)部就對(duì)這個(gè) Cocoa 錯(cuò)誤進(jìn)行“消化”,將它轉(zhuǎn)換為有意義的特定的某個(gè)已經(jīng)存在的 Error Reason。后者雖然減輕了 API 使用者的壓力,但是勢必會(huì)丟失一些信息,所以如果沒有特別理由的話,第一種的做法可能更加合適。

  • 錯(cuò)誤處理的 API 兼容存在風(fēng)險(xiǎn)
  • 現(xiàn)在來說,為 enum 添加一個(gè) case 的操作是無法做到 API 兼容的。使用側(cè)如果枚舉了所有的 case 進(jìn)行處理的話,在 case 增加時(shí),原來的代碼將無法編譯。(不過對(duì)于錯(cuò)誤處理來說,這倒可能對(duì)強(qiáng)制開發(fā)者對(duì)應(yīng)錯(cuò)誤情況是一種督促 233..)
  • 如果一個(gè)框架或者一套 API 嚴(yán)格遵守 semantic version 的話,這意味著一個(gè)大版本的更新。但是其實(shí)我們都心知肚明,增加一個(gè)之前可能忽略了的錯(cuò)誤情況,卻帶來一個(gè)大版本更新,帶來的麻煩顯然得不償失。
  • Swift 社區(qū)現(xiàn)在對(duì)于增加 enum case 時(shí)如何保持 API compatibility 也有一個(gè)成熟而且已經(jīng)被接受了的提案。將 enum 定義為 frozen 和 nonFrozen,并對(duì) nonFrozen 的 enum 使用 unknown 關(guān)鍵字來保證源碼兼容。我們?cè)谙聜€(gè)版本的 Swift 中應(yīng)該就可以使用這個(gè)特性了。

Result

不帶 Error 類型的優(yōu)缺點(diǎn)正好和上面相反。

相對(duì)于 Result<T, E: Error>,Result<T> 不在外部對(duì)錯(cuò)誤類型提出任何限制,API 的創(chuàng)建者可以擺脫 AnyError,直接將任意的 Error 作為 .failure 值使用。

但同時(shí)很明顯,相對(duì)的,一個(gè)最重要的特性缺失就是我們無法針對(duì)錯(cuò)誤類型的特點(diǎn)為 Result 進(jìn)行擴(kuò)展了。

結(jié)論

因?yàn)?Swift 并沒有提供使用協(xié)議類型作為泛型中特化的具體類型的支持,這導(dǎo)致在 API 的強(qiáng)類型嚴(yán)謹(jǐn)性和靈活性上無法取得兩端都完美的做法。硬要對(duì)比的話,可能 Result<T, E: Error> 對(duì)使用者更加友好一些,因?yàn)樗峁┝艘粋€(gè)定義錯(cuò)誤類型的機(jī)會(huì)。但是相對(duì)地,如果創(chuàng)建者沒有掌握好錯(cuò)誤類型的程度,而將多層嵌套的錯(cuò)誤傳遞時(shí),反而會(huì)增加使用者的負(fù)擔(dān)。同時(shí),由于錯(cuò)誤類型被限定,導(dǎo)致 API 的變更要比只定義了結(jié)果類型的 Result<T> 困難得多。

不過 Result 暫時(shí)看起來不太可能被添加到標(biāo)準(zhǔn)庫中,因?yàn)樗澈蟠嬖谝粋€(gè)更大的協(xié)程和整個(gè)語言的異步模型該如何處理錯(cuò)誤的話題。在有更多的實(shí)踐和討論之前,如果沒有革 命性和語言創(chuàng)新的話,對(duì)如何進(jìn)行處理的話題,恐怕很難達(dá)成完美的共識(shí)。

結(jié)論:錯(cuò)誤處理真的是一件相當(dāng)艱難的事情。

最近這半年,在不同項(xiàng)目里,我對(duì) Result<T, E: Error> 和 Result<T> 兩種方式都進(jìn)行了一些嘗試。現(xiàn)在看來,我會(huì)更多地選擇帶有錯(cuò)誤類型的 Result<T, E: Error> 的形式,特別是在開發(fā)框架或者需要嚴(yán)謹(jǐn)?shù)腻e(cuò)誤處理的時(shí)候。將框架中可能拋出的錯(cuò)誤進(jìn)行統(tǒng)一封裝,可以很大程度上減輕使用者的壓力,讓錯(cuò)誤處理的代碼更加健壯。如果設(shè)計(jì)得當(dāng),它也能提供更好的擴(kuò)展性。

以上就是Swift設(shè)計(jì)思想Result<T>與Result<T, E: Error>類型解析的詳細(xì)內(nèi)容,更多關(guān)于Swift Result類型設(shè)計(jì)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Swift和C語言混合編程教程

    Swift和C語言混合編程教程

    這篇文章主要介紹了Swift和C語言混合編程教程,介紹基本數(shù)據(jù)類型對(duì)比、指針、常量等內(nèi)容,需要的朋友可以參考下
    2014-07-07
  • Swift中static和class關(guān)鍵字的深入講解

    Swift中static和class關(guān)鍵字的深入講解

    這篇文章主要給大家介紹了關(guān)于Swift中static和class關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Swift中類與結(jié)構(gòu)的初始化示例解析

    Swift中類與結(jié)構(gòu)的初始化示例解析

    這篇文章主要為大家介紹了Swift中類與結(jié)構(gòu)的初始化解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-03-03
  • Swift中的高階函數(shù)功能作用示例詳解

    Swift中的高階函數(shù)功能作用示例詳解

    這篇文章主要為大家介紹了Swift中的高階函數(shù)功能作用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Swift方法調(diào)度之類的普通方法底層探究

    Swift方法調(diào)度之類的普通方法底層探究

    這篇文章主要介紹了Swift-方法調(diào)度-類的普通方法底層探究,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • IOS 實(shí)現(xiàn)簡單的彈幕功能

    IOS 實(shí)現(xiàn)簡單的彈幕功能

    本文主要介紹IOS 實(shí)現(xiàn)彈幕功能,這里給大家一個(gè)實(shí)例來展現(xiàn)彈幕功能,有需要的小伙伴可以參考下
    2016-07-07
  • Swift教程之類與結(jié)構(gòu)詳解

    Swift教程之類與結(jié)構(gòu)詳解

    這篇文章主要介紹了Swift教程之類與結(jié)構(gòu)詳解,本文講解了類和結(jié)構(gòu)的異同、結(jié)構(gòu)和枚舉類型是數(shù)值類型、類是引用類型、如何選擇使用類還是結(jié)構(gòu)、集合類型的賦值和復(fù)制操作等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • Swift調(diào)用Objective-C代碼

    Swift調(diào)用Objective-C代碼

    目前Swift語言所編寫的應(yīng)用才剛剛可以使用Xcode 6 GM版本提交,而Objective-C作為蘋果的主開發(fā)語言存在了很多年了。目前尚無成熟的Swift庫可用,所以當(dāng)前編寫應(yīng)用可以說基本離不開調(diào)用Objective-C代碼的情況。
    2014-09-09
  • Swift中風(fēng)味各異的類型擦除實(shí)例詳解

    Swift中風(fēng)味各異的類型擦除實(shí)例詳解

    你也許曾聽過類型擦除,甚至也使用過標(biāo)準(zhǔn)庫提供的類型擦除類型如 AnySequence,下面這篇文章主要給大家介紹了關(guān)于Swift中風(fēng)味各異的類型擦除的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Swift中用到extension的一些基本的擴(kuò)展功能講解

    Swift中用到extension的一些基本的擴(kuò)展功能講解

    這篇文章主要介紹了Swift的一些基本的擴(kuò)展功能,即extension關(guān)鍵字的使用,需要的朋友可以參考下
    2015-11-11

最新評(píng)論