Принять протокол для массива и словаря - PullRequest
0 голосов
/ 17 мая 2018

У меня есть следующий протокол:

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 голосов
/ 17 мая 2018

Причиной этой ошибки является конфликт между типом dict, выведенным компилятором, и типом, который вы упомянули при соответствии Array вашему protocol.

Когда вы пишете эту строку

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

Для компилятора это будет так, как показано ниже, где тип равен Array<Dictionary<String, String>>

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

Теперь, когда вы делаете dict.stringValue, компилятор сначала сопоставляет тип вызывающего объекта, т.е. dict, с типом, который вы определили во время соответствия Array с MyProtocol

Поскольку тип компилятора выводит, например, Array<Dictionary<String, String>> отличается от типа, который вы упомянули в соответствии, т.е., Array<Dictionary<String, Any>>, поэтому компилятор выдает ошибку.

Но когда вы объявляете переменную dict с явным типом, т.е. Array<Dictionary<String, Any>>, таким же, как вы определили для соответствия MyProtocol, тогда компилятор не видит никаких проблем, и ваш код работает просто отлично.

При соответствии Array/Dictionary - MyProtocol вы можете просто игнорировать установку типа Element, как показано ниже,

extension Array: MyProtocol {

    var stringValue: String {

        return "ArrayValue"
    }
}

extension Dictionary: MyProtocol {

    var stringValue: String {

        return "DictionaryValue"
    }
}
0 голосов
/ 17 мая 2018

Вы должны изменить ограничения реализации Array и Dictionary следующим образом:

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