在我的代码中,我正在传递字典。该字典可以包含错误字符串。喜欢这个
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 :(得分: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
会适得其反。但在许多情况下,您可以完全避免此问题(通过较早的类型过滤错误),或通过移动到函数来避免重复。