Swift -定义递归类型与Protocol

发布时间: 2017/3/5 13:51:33
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我想要给有效的 JSON 对象定义可序列化类型

例如如果一个 JSON 可以包含下列内容︰

String 
Number 
Array 
Object
Date
Boolean

我想要与有效类型定义Protocol

protocol JsonSerializable {
}

typealias JSONObject = [String : JsonSerializable]
typealias JSONArray = [JsonSerializable]

// foundation implements serializing numbers + strings + dates etc. to JSON
extension String : JsonSerializable {}
extension Int : JsonSerializable {}

// problem with defining dictionary and array of JSON-able types
extension Dictionary : JsonSerializable {}
...

问题是我怎样才能确保字典 (在编译时) 只包含可序列化类型

解决方法 1:

首先我想推荐你读中的赋权扩展 Swift 2︰ Protocol、 类型和子类 (Xcode 7 beta 2)。(因为它是为 beta 2 有过一些小的改动)

回到你的问题。为 Array :

extension Array where Element: JsonSerializable {
    var json: String { ... }
}

[1, 2, 3].json     // Valid
[true, false].json // Invalid; `Bool` doesn't conform to `JsonSerializable`.

字典是有点棘手,因为,正如在上述文章中所说︰

现行规则以及扩展泛型类型以这种方式是,被引用的类型后 where 关键字必须是一类或一种Protocol。

因此,您不能指定的 KeyDictionary 必须是 String 。在这篇文章中给出的解决方法是定义 StringType Protocol︰

protocol StringType {
    var characters: String.CharacterView { get }
}
extension String: StringType {}

现在的字典扩展︰

extension Dictionary where Key: StringType, Value: JsonSerializable {
    var json: String { ... }
}

["A": 1, "B": 2].json        // Valid
[1: "1", 2: "2"].json        // Invalid; `Int` doesn't conform to `StringType`.
["A": true, "B": false].json // Invalid; `Bool` doesn't conform to `JsonSerializable`.

或者,您可以创建您自己 JsonArrayJsonDictionary 类型,将支持由 ArrayDictionary 分别︰

struct JsonArray<Element: JsonSerializable> {
    private var array: [Element]
    ...
}

extension JsonArray: ArrayLiteralConvertible {
    init(arrayLiteral elements: Element...) {
        self.init(array: elements)
    }
}

struct JsonDictionary<Value: JsonSerializable> {
    private var dictionary: [String: Value]
    ...
}

extension JsonDictionary: DictionaryLiteralConvertible {
    init(dictionaryLiteral elements: (String, Value)...) {
        var temp = [String: Value]()
        for (key, value) in elements {
            temp[key] = value
        }

        self.init(dictionary: temp)
    }
}

let array: JsonArray = [1, 2, 3]
let dictionary: JsonDictionary = ["A": 1, "B": 2]
官方微信
官方QQ群
31647020