Операнды типа Generi c в пользовательском операторе Swift - PullRequest
0 голосов
/ 09 января 2020

Моя цель - создать оператор, который позволит мне легко объединять Dictionary значения, например:

["a" : "A"] + ["b" : "B"]

Моя попытка ниже:

extension Dictionary {
    public static func +=<K, V>(lhs: inout Dictionary<K, V>, rhs: Dictionary<K, V>?) {
        if let rhs = rhs {
            lhs.merge( rhs )
        }
    }

    public static func +=<K, V>(lhs: inout Dictionary<K, V>?, rhs: Dictionary<K, V>) {
        if var lhs = lhs {
            lhs.merge( rhs )
        }
        else {
            lhs = rhs
        }
    }

    public static func +<K, V>(lhs: Dictionary<K, V>, rhs: Dictionary<K, V>?) -> Dictionary<K, V> {
        if let rhs = rhs {
            return lhs.merging( rhs )
        }

        return lhs
    }

    public static func +<K, V>(lhs: Dictionary<K, V>?, rhs: Dictionary<K, V>) -> Dictionary<K, V> {
        if let lhs = lhs {
            return lhs.merging( rhs )
        }

        return rhs
    }

    @inlinable public mutating func merge(_ other: [Key: Value]) {
        self.merge( other, uniquingKeysWith: { $1 } )
    }

    @inlinable public func merging(_ other: [Key: Value]) -> [Key: Value] {
        self.merging( other, uniquingKeysWith: { $1 } )
    }
}

Это не появляется работать (по состоянию на Swift 5), и я подозреваю, что проблема связана с типом Dictionary, являющимся универсальным типом c. Кто-нибудь, кто может объяснить, что мешает этому работать, и есть ли альтернативное решение / подход, который может работать?

1 Ответ

3 голосов
/ 09 января 2020

Проблема в том, что вы создаете новые типы значений generi c K, V. Все, что вам нужно, это опустить их в декларации методов. Кстати, вы забыли добавить метод для суммирования двух необязательных словарей:

extension Dictionary {

    public static func +=(lhs: inout Dictionary, rhs: Dictionary) {
         lhs.merge(rhs)
    }
    public static func +=(lhs: inout Dictionary, rhs: Dictionary?) {
        if let rhs = rhs { lhs.merge(rhs) }
    }
    public static func +=(lhs: inout Dictionary?, rhs: Dictionary) {
        if var lhs = lhs { lhs.merge(rhs) } else { lhs = rhs }
    }

    public static func +(lhs: Dictionary, rhs: Dictionary) -> Dictionary {
        lhs.merging(rhs)
    }
    public static func +(lhs: Dictionary, rhs: Dictionary?) -> Dictionary {
        if let rhs = rhs { return lhs.merging(rhs) }
        return lhs
    }
    public static func +(lhs: Dictionary?, rhs: Dictionary) -> Dictionary {
        if let lhs = lhs { return lhs.merging(rhs) }
        return rhs
    }

    @inlinable public mutating func merge(_ other: Dictionary) {
        self.merge(other) {$1}
    }

    @inlinable public func merging(_ other: Dictionary) -> Dictionary {
        self.merging(other) {$1}
    }
}

let dicSum = ["a" : "A"] + ["b" : "B"]

dicSum  // ["b": "B", "a": "A"]

Альтернативой является создание typealiases для словаря generi c Key и Value типов и удаление те, которые вы создали в объявлении ваших методов <K,V>, иначе они будут снова новым обобщенным типом c, не связанным с определенными в Словаре объявление :

extension Dictionary {

    public typealias K = Key
    public typealias V = Value

    public static func +=(lhs: inout [K: V], rhs: [K: V]) {
         lhs.merge(rhs)
    }
    public static func +=(lhs: inout [K: V], rhs: [K: V]?) {
        if let rhs = rhs { lhs.merge(rhs) }
    }
    public static func +=(lhs: inout [K: V]?, rhs: [K: V]) {
        if var lhs = lhs { lhs.merge(rhs) } else { lhs = rhs }
    }

    public static func +(lhs: [K: V], rhs: [K: V]) -> [K: V] {
        lhs.merging(rhs)
    }
    public static func +(lhs: [K: V], rhs: [K: V]?) -> [K: V] {
        if let rhs = rhs { return lhs.merging(rhs) }
        return lhs
    }
    public static func +(lhs: [K: V]?, rhs: [K: V]) -> [K: V] {
        if let lhs = lhs { return lhs.merging(rhs) }
        return rhs
    }

    @inlinable public mutating func merge(_ other: [K: V]) {
        self.merge(other) {$1}
    }

    @inlinable public func merging(_ other: [K: V]) -> [K: V] {
        self.merging(other) {$1}
    }
}

точно так же, как это делается выше.


Опять же Dictionary, Dictionary<Key, Value> и [Key:Value] - это абсолютно одно и то же:

extension Dictionary {

    public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) {
         lhs.merge(rhs)
    }
    public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]?) {
        if let rhs = rhs { lhs.merge(rhs) }
    }
    public static func +=(lhs: inout [Key: Value]?, rhs: [Key: Value]) {
        if var lhs = lhs { lhs.merge(rhs) } else { lhs = rhs }
    }

    public static func +(lhs: [Key: Value], rhs: [Key: Value]) -> [Key: Value] {
        lhs.merging(rhs)
    }
    public static func +(lhs: [Key: Value], rhs: [Key: Value]?) -> [Key: Value] {
        if let rhs = rhs { return lhs.merging(rhs) }
        return lhs
    }
    public static func +(lhs: [Key: Value]?, rhs: [Key: Value]) -> [Key: Value] {
        if let lhs = lhs { return lhs.merging(rhs) }
        return rhs
    }

    @inlinable public mutating func merge(_ other: [Key: Value]) {
        self.merge(other) {$1}
    }

    @inlinable public func merging(_ other: [Key: Value]) -> [Key: Value] {
        self.merging(other) {$1}
    }
}

Все 3 способа его реализации эквивалентны. Выберите тот, который вам удобнее.

...