混合构造器
今天的内容非常简单,但是有些内容会让人产生困扰,通常出现在 extensions 的上下文或者和 无法委托给可失败的构造器比如说你有个带有可失败构造器的类型。现在你想扩展这个类型让他支持反序列化 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 数据时(这是不常见的对吧?),编译器会帮助我们将这个构造器转换到一个可失败的构造器,或者是插入一个不安全的解包类型,然后会终止掉。 其次,即便我们可以检查可失败构造器的结果,但没有语法可以这样做。 针对这个情况有三种解决方案: 1.如果拥有对应的类型,可以将实际初始化的代码移到一个私有的可抛出异常的构造器里面,然后公开的构造器都委托它来进行初始化。在可失败构造器里面使用 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.如果不拥有类型并且它是一个值类型,你可以对 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.如果不拥有类型并且它是一个引用类型,那么你必须使用一个静态方法来解决,因为你没有更好的选择了。 原始值上面的技巧同样适用于含有原始值(RawValue)的枚举值。即使你拥有类型,你也不拥有自动生成的构造器,所以只能对 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
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |