Swift-使用协议定义递归类型 [英] Swift - define a recursive type with a protocol

查看:107
本文介绍了Swift-使用协议定义递归类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想定义一个可以序列化为有效JSON对象的类型

I want to define a type that can be serialized to a valid JSON object

例如,如果JSON可以包含以下内容:

So for instance if a JSON can contain the following:

String 
Number 
Array 
Object
Date
Boolean

我想定义一个具有有效类型的协议

I would like to define a protocol with valid types

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 {}
...

问题是我如何确保字典仅包含可序列化类型(在编译时)

The question is how can I make sure that the dictionary only contains serializable types (at compile time)

推荐答案

首先,我建议您阅读

Firstly I would recommend you read Empowering Extensions in Swift 2: Protocols, Types and Subclasses (Xcode 7 beta 2). (Since it's for beta 2 there have been a few minor changes)

回到您的问题.对于Array:

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

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

字典有点棘手,因为,正如所提到的文章所述:

Dictionary is a bit trickier because, as said in the mentioned article:

以这种方式扩展通用类型的当前规则是: 在where关键字必须是类或a之后引用的类型 协议.

The current rules of extending a generic type in this way is that the type being referenced after the where keyword must be a class or a protocol.

因此,您不能指定DictionaryKey必须是String.本文中给出的解决方法是定义StringType协议:

Therefore you can't specify that the Key of the Dictionary must be a String. The workaround given in the article is to define a 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支持:


Alternatively, you could create your own JsonArray and JsonDictionary types, which would be backed by an Array or Dictionary respectively:

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]

这篇关于Swift-使用协议定义递归类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆