做者:Russ Bishop,原文连接,原文日期:2016-11-09
译者:Cyan;校对:小铁匠Linus;定稿:CMBgit
今天的内容很是简单,可是有些内容会让人产生困扰,一般出如今 extensions 的上下文或者和 RawRepresentable
的枚举值打交道的时候。github
好比说你有个带有可失败构造器的类型。如今你想扩展这个类型让他支持反序列化 JSON 数据。当 JSON 解析失败的时候抛出一个友好且详细的错误,而且你但愿发生任何错误的时候都可以抛出来,无论是 JSON 解析仍是可失败初始化器中的错误,若是咱们能抛出异常的话那是很好的。json
struct FizzFail { init?(string: String) { /* magic */ } init(json: JsonValue) throws { // 解析 json guard let string = json.string else { throw JsonError.invalidJson } // 错误:不可失败的构造器没法委托给可失败的构造器 if self.init(string: string) == nil { throw JsonError.missingValue } } }
这里有两个问题。首先是咱们不能委托给可失败构造器。当有人尝试传递一个不合法的 JSON 数据时(这是不常见的对吧?),编译器会帮助咱们将这个构造器转换到一个可失败的构造器,或者是插入一个不安全的解包类型,而后会终止掉。swift
其次,即使咱们能够检查可失败构造器的结果,但没有语法能够这样作。self
在可失败构造器的上下文中只是一个可选值。安全
针对这个状况有三种解决方案:.net
1.若是拥有对应的类型,能够将实际初始化的代码移到一个私有的可抛出异常的构造器里面,而后公开的构造器都委托它来进行初始化。在可失败构造器里面使用 try?
来忽略错误。翻译
struct Fizz { private init(value: String) throws { /* magic */ } init(json: JsonValue) throws { guard let string = json.string else { throw JsonError.invalidJson } try self.init(value: string) } init?(string: String) { try? self.init(value: string) } }
2.若是不拥有类型而且它是一个值类型,你能够对 self
从新赋值。这会致使额外的声明和分配,可是代码看起来会更清晰。code
extension FizzFail { init(json: JsonValue) throws { // 解析 json guard let string = json.string, let value = type(of: self).init(string: string) else { throw JsonError.invalidJson } self = value } }
3.若是不拥有类型而且它是一个引用类型,那么你必须使用一个静态方法来解决,由于你没有更好的选择了。get
上面的技巧一样适用于含有原始值(RawValue)的枚举值。即便你拥有类型,你也不拥有自动生成的构造器,因此只能对 self
从新赋值:编译器
enum Buzz: String { case wat = "wat" case other = "other" private enum ConstructionError: Error { case invalidConstruction } init(string: String) { if let value = type(of: self).init(rawValue: string) { self = value } else { self = .other } } }
我在 30 分钟里写完了这篇文章是为了让你知道,其实个人博客还在维护,最后谢谢你读完。
Russ Bishop
这个博客仅表明我我的的观点,并无获得个人雇主的承认。
本文由 SwiftGG 翻译组翻译,已经得到做者翻译受权,最新文章请访问 http://swift.gg。