2017-09-26 48 views
0

在我的代碼中,我正在傳遞一個字典。該字典可以包含錯誤字符串。像這樣當測試某個屬性的存在時,正確使用警衛

func handleSomething(_ json: [String: Any]) -> (Bool, String?) { 
    if let error = json["error"] as? String { 
     print("I have an error: \(error)") 
     return (false, error) 
    } 
    ... 
    return (true, nil) 
} 

我認爲這是使用後衛的好地方,但是代碼不簡明

func handleSomething(_ json: [String: Any]) -> Bool { 
    let error = json["error"] as? String 
    guard error == nil else { 
     print("I have an error: \(error!)") 
     return (false, error) 
    } 
    ... 
    return (true, nil) 
} 

有沒有更好的方式來做到這一點,因此分配和檢查能在一行中完成?如果不是這是警衛的正確使用?

更新:增加了返回值以更好地說明問題的真實意圖。

+0

閱讀:https://stackoverflow.com/a/32256911/771231 – Desdenova

+1

只是保持第一個變體,不要想太多。 – Sulthan

+1

不需要使用警衛和/或如果有條件。只要返回'json [「error」] == nil' –

回答

2

一般而言,您應該避免在[String: Any]附近傳遞。你應該分析,這歸因於更強的數據類型前面,你應該分離出錯誤的情況下出現,往往與一個枚舉:

struct ServerData { 
    // good data; no errors 
} 

enum ServerResponse { 
    case success(ServerData) 
    case error(String) // Return this if error is set 
} 

有了這個,我們的職能將只取ServerData居多,所以錯誤已經被處理用。只要有可能,而不是提出巧妙的解決方法來解決問題,讓整個問題消失。

也就是說,仍然有解析器本身需要處理,這種情況可能會出現在這裏,甚至當你有更強的類型。在很多情況下,你經常會遇到這種守衛/日誌模式,這絕對值得避免。因此,拉出一個功能:

func noErrorOrLog(_ json: [String: Any]) -> Bool { 
    if let error = json["error"] as? String { 
     print("I have an error: \(error)") 
     return false 
    } 

    return true 
} 

現在實際的處理函數可以使用guard和避免重複記錄:

func handleSomething(_ json: [String: Any]) -> Bool { 
    guard noErrorOrLog(json) else { 
     return false 
    } 
    // ... 
} 

在某些情況下,這是沒有意義的(如果你正是這樣做一次也許),在這種情況下if-let是正確的工具。創建混淆代碼來創建guard會適得其反。但在很多情況下,您可以完全避免此問題(通過使用強類型提前過濾錯誤),或通過移至函數來避免重複。

+0

我會同意這是更好的,但是如果(並在我的真實代碼)我想傳回錯誤代碼(使用返回語句或回調)。在我的生產代碼中,這是錯誤可以被處理的最早點(API的響應) – datinc

+0

個人而言,我可能會在那裏使用'throws',這使得'try noErrorOrThrow(payload)'函數非常容易。不需要警衛。 –