采用数组和字典的协议

时间:2018-05-17 07:13:04

标签: arrays swift generics swift-protocols swift4.1

我有以下协议:

protocol MyProtocol {

    var stringValue: String { get }
}

我还为扩展中的一些类和结构实现了它的方法:

extension Int: MyProtocol {

    var stringValue: String {

        return "IntValue"
    }
}

extension String: MyProtocol {

    var stringValue: String {

        return "StringValue"
    }
}

extension Array: MyProtocol where Element == Dictionary<String, Any> {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol where Key == String, Value == Any {

    var stringValue: String {

        return "DictionaryValue"
    }
}

当我尝试使用以下代码进行测试时:

let dict = [["key":"value"]]
let stringValueResult = dict.stringValue
print(stringValueResult)

我收到错误,文字“[[String : String]]无法转换为Array<Dictionary<String, Any>>”。但是,当我设置变量dict的类型时,我的代码工作正常:

let dict: Array<Dictionary<String, Any>> = [["key":"value"]]

有人可以解释为什么我的代码的第一个版本没有编译吗?

2 个答案:

答案 0 :(得分:1)

您应该更改ArrayDictionary实施约束,如下所示:

extension Array: MyProtocol where Element: MyProtocol {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol where Key == String {

    var stringValue: String {

        return "DictionaryValue"
    }
}

现在,如果您运行以下代码,则会打印:ArrayValue

let dict = [["key":"value"]]
let stringValueResult = dict.stringValue
print(stringValueResult)

答案 1 :(得分:0)

此错误的原因是编译器推断的dict类型与您在Array符合protocol时提到的类型之间的冲突。

当你写这行时

let dict = [["key":"value"]]  

对于编译器,它将变为如下类型Array<Dictionary<String, String>>

let dict: Array<Dictionary<String, String>> = [["key":"value"]]

现在,当您执行dict.stringValue时,编译器将首先匹配调用对象的类型,即dict与您在ArrayMyProtocol <的一致性期间定义的类型/ p>

由于编译器推断类型,即Array<Dictionary<String, String>>与您在一致性中提到的类型不同,即Array<Dictionary<String, Any>>,因此编译器会抛出错误。

但是当您使用显式类型声明dict变量时,Array<Dictionary<String, Any>>与您在MyProtocol的一致性中定义的相同,那么编译器看不到任何问题,并且您的代码工作正常。< / p>

Array/Dictionary符合MyProtocol的同时,您可以忽略设置Element类型,如下所示

extension Array: MyProtocol {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol {

    var stringValue: String {

        return "DictionaryValue"
    }
}