12

私はこの機能を持っています:

func flatten<Key: Hashable, Value>(dict: Dictionary<Key, Optional<Value>>) -> Dictionary<Key, Value> {
    var result = [Key: Value]()
    for (key, value) in dict {
        guard let value = value else { continue }
        result[key] = value
    }
    return result
}

ご覧のとおり、[Key: Value?]辞書を辞書に変換し[Key: Value]ます (オプションなし)。

Dictionary値が任意の型のクラスに対してのみ新しいメソッドを使用してクラスを拡張したかったOptionalのですが、辞書の汎用パラメーターに制約を追加できません。

これは私が試したものです:

extension Dictionary where Value: Optional<Any> {
    func flatten() -> [Key: Any] {
        var result = [Key: Any]()
        for (key, value) in self {
            guard let value = value else { continue }
            result[key] = value
        }
        return result
    }
}

しかし、エラーで失敗します:

Type 'Value' constrained to non-protocol type 'Optional<Any>'
4

2 に答える 2

16

Playground で次のコードを試してください。

// make sure only `Optional` conforms to this protocol
protocol OptionalEquivalent {
  typealias WrappedValueType
  func toOptional() -> WrappedValueType?
}

extension Optional: OptionalEquivalent {
  typealias WrappedValueType = Wrapped

  // just to cast `Optional<Wrapped>` to `Wrapped?`
  func toOptional() -> WrappedValueType? {
    return self
  }
}

extension Dictionary where Value: OptionalEquivalent {
  func flatten() -> Dictionary<Key, Value.WrappedValueType> {
    var result = Dictionary<Key, Value.WrappedValueType>()
    for (key, value) in self {
      guard let value = value.toOptional() else { continue }
      result[key] = value
    }
    return result
  }
}

let a: [String: String?] = ["a": "a", "b": nil, "c": "c", "d": nil]
a.flatten() //["a": "a", "c": "c"]

プロトコル拡張の節で正確なタイプを指定することはできないため、タイプをwhere正確に検出する 1 つの方法は、 UNIQUELY をプロトコルに準拠させることです (たとえば、)。OptionalOptionalOptionalEquivalent

のラップされた値の型を取得するために、カスタム プロトコルでOptionaltypealias を定義してから Optional の拡張を作成し、to を代入すると、 flatten メソッドで型を取得できます。WrappedValueTypeOptionalEquivalentWrappedWrappedValueType

メソッドはtosugarCastをキャストするだけであることに注意してください(これはまったく同じことです)、使用法ステートメントを有効にします。Optional<Wrapped>Wrapped?guard

アップデート

Rob Napier のコメントのおかげで、sugarCast() メソッドを簡略化して名前を変更し、プロトコルの名前を変更して、より理解しやすくしました。

于 2015-10-30T13:16:20.660 に答える