2017-07-20 9 views
1

2つの辞書を深くマージする関数を作成しようとしています。これにより、両方の辞書のキーの値がマージされ、それらの値が両方とも辞書である場合、一方が他方に置換される代わりにマージされることを意味する。ここで2つの辞書を深くマージするための一般的なSwift拡張機能を作成するにはどうすればよいですか?

は、私が持っているものです。

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 
    } 
} 

しかし残念ながら、それはコンパイルされません。私はエラーを受け取ります

'deepMerged(with :)への再帰呼び出しで、値の使用に関して' [Key:Value] 'を予想される引数型[_:_]'に変換できません。私は拡張子をスコープによって、この問題を回避することができるよ

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

これは、この時点で私の特定のユースケースのために動作しますが、より一般的なコードは」doesnの理由を私は理解していません仕事。エラーがresult[key]への代入であることを

答えて

2

注意、ない機能に自分自身を呼び出す:

  • result[Key: Value]
  • otherは次のとおりです。

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

    コンパイラがあることを知っています[Key: Value]

  • keyは、Key
  • valueValue
  • mergedある[Key:Value]
  • resultsubscript(key: Key) -> Value? { get set }(即ち、を有していますKeyを受け入れるタイプValue?の書き込み可能な添字)

しかし、それははそれがmergedresultの添字に渡すことができることを知らないように[Key:Value]は、Valueであることを知っているしません。 valueValueであり、value[Key: Value]であるため、[Key: Value]Valueである必要がありますが、コンパイラはそのことを認識していません。

ソリューションは、Valuemergedをキャストすることです:

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 
    } 
} 
関連する問題