swift - 用幻像类型解码泛型

标签 swift generics codable phantom-types

我正在尝试定义一个 Currency 类型,以防止混淆数字和字母货币代码:

public protocol ISO4217Type {}

public enum ISO4217Alpha: ISO4217Type {}
public enum ISO4217Num: ISO4217Type {}

public struct Currency<T: ISO4217Type> {

    public let value: String
}

extension Currency where T == ISO4217Alpha {

    public init?(value: String) {
        let isLetter = CharacterSet.letters.contains
        guard value.unicodeScalars.all(isLetter) else { return nil }
        self.value = value
    }
}

extension Currency where T == ISO4217Num {

    public init?(value: String) {
        let isDigit = CharacterSet.decimalDigits.contains
        guard value.unicodeScalars.all(isDigit) else { return nil }
        self.value = value
    }
}

这很好用。现在,是否可以添加 Codable 一致性,当尝试使用错误的有效负载解码货币代码时会抛出解码错误? (例如,将 USD 解码为数字货币代码。)

最佳答案

关键的启示是可以在幻像类型上使用静态函数来自定义行为:

public protocol ISO4217Type {

    static func isValidCode(_ code: String) -> Bool
}

public enum ISO4217Alpha: ISO4217Type {

    public static func isValidCode(_ code: String) -> Bool {
        let isLetter = CharacterSet.letters.contains
        return code.unicodeScalars.all(isLetter)
    }
}

public enum ISO4217Num: ISO4217Type {

    public static func isValidCode(_ code: String) -> Bool {
        let isDigit = CharacterSet.decimalDigits.contains
        return code.unicodeScalars.all(isDigit)
    }
}

public struct Currency<T: ISO4217Type> {

    public let value: String

    private init(uncheckedValue value: String) {
        self.value = value
    }

    public init?(value: String) {
        guard T.isValidCode(value) else { return nil }
        self.value = value
    }
}

extension Currency: Codable {

    public func encode(to encoder: Encoder) throws {
        var c = encoder.singleValueContainer()
        try c.encode(value)
    }

    public init(from decoder: Decoder) throws {
        let c = try decoder.singleValueContainer()
        let value = try c.decode(String.self)
        guard T.isValidCode(value) else {
            throw DecodingError.dataCorruptedError(in: c,
                debugDescription: "Invalid \(type(of: T.self)) code")
        }
        self.init(uncheckedValue: value)
    }
}

关于swift - 用幻像类型解码泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47469518/

相关文章:

ios - 如何将 CodingKeys 用于符合 Codable 协议(protocol)的枚举?

swift - 如何在核心数据中使用 swift 4 Codable?

ios - UITableView 不会更新数据

generics - 为什么具有泛型类型参数的 trait 方法是对象不安全的?

scala - Scala 中的高级类型是什么?

haskell - 如何一般地提取 Haskell 记录中的字段名称和值

iOS 在后台显示本地通知弹出窗口

ios - iPhone 8 和 iPhone X 的不同视角

ios - 使用 MKGeodesicPolyline Swift 3 计算距离将出现错误

ios - Codable 句柄单个或数组