2017-07-20 7 views
1

Ich versuche, eine Funktion zum tiefen Zusammenführen zweier Wörterbücher zu schreiben. Damit meine ich, dass, wenn die Werte für einen Schlüssel in beiden Wörterbüchern zusammengeführt werden und diese Werte beide Wörterbücher sind, sie zusammengeführt werden, anstatt dass eines durch das andere ersetzt wird.Wie schreibe ich eine generische Swift-Erweiterung, um zwei Wörterbücher zu vertiefen?

Hier ist, was ich habe:

extension Dictionary { 
    public func deepMerged(with other: [Key: Value]) -> [Key: Value] { 
     var result: [Key: Value] = self 
     for (key, value) in other { 
      if let value = value as? [Key: Value], let existing = result[key] as? [Key: Value] { 
       result[key] = existing.deepMerged(with: value) 
      } else { 
       result[key] = value 
      } 
     } 
     return result 
    } 
} 

Aber leider ist es nicht kompilieren. Ich erhalte die Fehler

nicht Wert vom Typ umwandeln kann ‚[Schlüssel: Wert]‘ zu erwarten Argument Typen [_: _]‘auf der Verwendung von Wert in dem rekursiven Aufruf` deepMerged (mit :).

ich in der Lage bin von Scoping die Erweiterung, um dieses Werk:

extension Dictionary where Key == String, Value == Any { 
    ... 
} 

Dies funktioniert für meinen speziellen Anwendungsfall zu diesem Zeitpunkt, aber ich verstehe nicht, warum der allgemeineren Code doesn‘ t arbeiten.

Antwort

2

Beachten Sie, dass der Fehler auf der Zuordnung zu result[key], nicht auf die Funktion selbst nennen:

let merged: [Key:Value] = existing.deepMerged(with: value) //works fine 
result[key] = merged          //error 

Der Compiler weiß, dass:

  • result ein [Key: Value] ist
  • other a [Key: Value]
  • key ist ein Key
  • value ist ein Value
  • merged ist ein [Key:Value]
  • result eine subscript(key: Key) -> Value? { get set } hat (d.h. ein beschreibbares Index vom Typ Value?, die ein Key)

Aber es nicht weiß, dass [Key:Value] ist ein Value, so dass er nicht weiß, dass merged akzeptiert kann den Index von result weitergegeben werden. Da value ist ein Value und value ist auch [Key: Value], wir wissen, dass [Key: Value] muss ein Value sein, aber der Compiler weiß das nicht.

Eine Lösung ist merged zu einer Value gegossen:

extension Dictionary { 
    public func deepMerged(with other: [Key: Value]) -> [Key: Value] 
    { 
     var result: [Key: Value] = self 
     for (key, value) in other { 
      if let value = value as? [Key: Value], 
       let existing = result[key] as? [Key: Value], 
       let merged = existing.deepMerged(with: value) as? Value 
      { 
       result[key] = merged 
      } else { 
       result[key] = value 
      } 
     } 
     return result 
    } 
} 
Verwandte Themen