混合构造器

做者: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

相关文章
相关标签/搜索