简体   繁体   English

具有泛型类型的 Swift 协议

[英]Swift protocol with generic types

I'm trying to create a protocol that has a static method that returns a generic type.我正在尝试创建一个具有返回泛型类型的静态方法的协议。 In most cases what I have seems to work reasonably well.在大多数情况下,我所拥有的似乎工作得相当好。 The challenge comes in when I want to use an extension to return this generic value.当我想使用扩展来返回这个通用值时,挑战就来了。 Here's what I have.这就是我所拥有的。 This code can be placed into a playground.这段代码可以放在一个操场上。

Here's the first protocol I want which contains the associatedtype这是我想要的第一个包含associatedtype协议

protocol AWSerializable {
    associatedtype T

    static func deserialize(dictionary: [String : Any]) -> T?
    func serialize() -> [String : Any]
}

Then I created another protocol which allows me to create instances that do the action of deserializing:然后我创建了另一个协议,它允许我创建执行反序列化操作的实例:

protocol AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T?
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]?
}

Here is an example that happily implements the AWSerializable protocol:这是一个愉快地实现AWSerializable协议的例子:

class FooBar: AWSerializable {

    typealias T = FooBar

    var foo = ""
    var bar = ""

    static func deserialize(dictionary: [String : Any]) -> FooBar? {
        let fooBar = FooBar()

        fooBar.foo = (dictionary["foo"] as? String) ?? ""
        fooBar.bar = (dictionary["bar"] as? String) ?? ""

        return fooBar
    }

    func serialize() -> [String : Any] {
        var serialized = [String : Any]()

        serialized["foo"] = foo
        serialized["bar"] = bar

        return serialized
    }

}

So far so good.到现在为止还挺好。 The challenge comes in when I want to create an extension on UserDefaults to implement the AWDeserializer protocol.当我想在UserDefaults上创建一个extension来实现AWDeserializer协议时,挑战就来了。

extension UserDefaults: AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? {
        if let serialized = UserDefaults.standard.object(forKey: key) as? [String : Any] {
            return T.deserialize(dictionary: serialized)
        }

        return nil
    }

    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? {
        if let data = UserDefaults.standard.array(forKey: key) as? [[String : Any]] {
            var values = [T]()

            for entry in data {
                if let value = T.deserialize(dictionary: entry) {
                    values.append(value)
                }
            }

            return values
        }

        return nil
    }
}

The problem here is with T.deserialize(dictionary: serialized) .这里的问题在于T.deserialize(dictionary: serialized) I get the following error:我收到以下错误:

在此处输入图片说明

This is easily fixed by applying the suggested solution, or preferably by changing the line to return T.deserialize(dictionary: serialized) as? T通过应用建议的解决方案,或者最好通过更改行以return T.deserialize(dictionary: serialized) as? T return T.deserialize(dictionary: serialized) as? T

But I don't like the fact that this optional cast is required to begin with.但我不喜欢这个可选的演员表必须开始的事实。 Is there a way to define the protocols that doesn't require this cast?有没有办法定义不需要这种转换的协议?

Maybe it's much better to use this protocol AWDeserializer :也许使用这个协议AWDeserializer

protocol AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T
}

Instead of:代替:

protocol AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T?
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]?
}

And here is the rest of code:这是其余的代码:

protocol AWSerializable {
    associatedtype T

    static func deserialize(dictionary: [String : Any]) -> T?
    func serialize() -> [String : Any]
}

protocol AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T
}

class FooBar: AWSerializable {

    typealias T = FooBar

    var foo = ""
    var bar = ""

    static func deserialize(dictionary: [String : Any]) -> FooBar? {
        let fooBar = FooBar()

        fooBar.foo = (dictionary["foo"] as? String) ?? ""
        fooBar.bar = (dictionary["bar"] as? String) ?? ""

        return fooBar
    }

    func serialize() -> [String : Any] {
        var serialized = [String : Any]()

        serialized["foo"] = foo
        serialized["bar"] = bar

        return serialized
    }

}

extension UserDefaults: AWDeserializer {
    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> T? where T.T == T {
        if let serialized = UserDefaults.standard.object(forKey: key) as? [String : Any] {
            return T.deserialize(dictionary: serialized)
        }

        return nil
    }

    func deserializeWithKey<T: AWSerializable>(_ key: String!) -> [T]? where T.T == T  {
        if let data = UserDefaults.standard.array(forKey: key) as? [[String : Any]] {
            var values = [T]()

            for entry in data {
                if let value = T.deserialize(dictionary: entry) {
                    values.append(value)
                }
            }

            return values
        }

        return nil
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM