Reputation: 4521
I have the following protocol:
protocol MyProtocol {
var stringValue: String { get }
}
I also implemented it's methods for some classes and structures in extensions:
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"
}
}
When I tried to test it with the following code:
let dict = [["key":"value"]]
let stringValueResult = dict.stringValue
print(stringValueResult)
I received an error with text "[[String : String]]
is not convertible to Array<Dictionary<String, Any>>
". However my code works fine when I set type of the variable dict
like that:
let dict: Array<Dictionary<String, Any>> = [["key":"value"]]
Can someone explain me why the first version of my code is not compiling?
Upvotes: 0
Views: 301
Reputation: 15238
The reason for this error is the conflict between the dict
type inferred by the compiler and the one you mentioned while conforming Array
to your protocol
.
When you write this line
let dict = [["key":"value"]]
For compiler it will become as below where type is Array<Dictionary<String, String>>
let dict: Array<Dictionary<String, String>> = [["key":"value"]]
Now when you are doing dict.stringValue
, compiler will first match the type of the calling object i.e dict
with the type you defined during conformance of Array
with MyProtocol
As the compiler inferred type i.e, Array<Dictionary<String, String>>
is different than the type you mentioned in conformance i.e, Array<Dictionary<String, Any>>
so compiler throws error.
But when you declare dict
variable with explicit type i.e, Array<Dictionary<String, Any>>
same as you defined in conformance of MyProtocol
then compiler does not see any issue and your code works just fine.
While conforming Array/Dictionary
to MyProtocol
you can just ignore setting the Element
type as below,
extension Array: MyProtocol {
var stringValue: String {
return "ArrayValue"
}
}
extension Dictionary: MyProtocol {
var stringValue: String {
return "DictionaryValue"
}
}
Upvotes: 0
Reputation: 2902
You should change your Array
and Dictionary
implementation constraint like this:
extension Array: MyProtocol where Element: MyProtocol {
var stringValue: String {
return "ArrayValue"
}
}
extension Dictionary: MyProtocol where Key == String {
var stringValue: String {
return "DictionaryValue"
}
}
Now if you run following code it will print: ArrayValue
let dict = [["key":"value"]]
let stringValueResult = dict.stringValue
print(stringValueResult)
Upvotes: 1