Swift - define a recursive type with a protocol

我与影子孤独终老i 提交于 2019-12-06 18:57:26

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)

Back to your problem. For 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:

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.

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

Now for the Dictionary Extension:

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`.

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]

As far as I know, it is impossible today in Xcode 7 beta 6.

You can duplicate this radar if you want: http://openradar.appspot.com/radar?id=5623386654900224

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!