web-dev-qa-db-ja.com

クロージャータプルは、Xcode 9での破壊をサポートしていませんSwift 4

Xcode 9のSwift 4の光沢プロジェクトの後

私は知らない次のエラーを取得しています

クロージャータプルパラメーター '(key:_、value:_)'は、構造化をサポートしていません

コード:

_extension Dictionary
{
    init(elements: [Element]) {
        self.init()
        for (key, value) in elements {
            self[key] = value
        }
    }

    func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] {
        return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ (key, value) in
            return try transform(key, value)
        }))
    }
}
_

この時点でエラーが発生しますtry flatMap({ (key, value)in

28
Mihir Mehta

次の辞書のflatMapの定義から始めましょう。

func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

transformクロージャーは、1つのパラメータータイプElementのみを取ります。ここで、Elementは、タプルのtypealiasにすぎません。

public typealias Element = (key: Key, value: Value)

したがって、クロージャーの最初のおよび唯一引数は、2つの要素のタプル(key型のKeyおよびvalue型のValue)でなければなりません。


さて、コードを見ると(Swift 3でコンパイルされます)、そうではないことがわかります。Swift 3でもこれが機能する理由を尋ねる必要があります。

try flatMap({ (key, value) in
    return try transform(key, value)
})

クロージャーは、1つではなく2つの引数を取ります(key型のKeyおよびvalue型のValue)。これはSwift 3で機能します。これは、コンパイラが2要素のタプルを2つの引数に自動的に変換するdestructuringという機能のおかげです。

しかし、この機能は奇妙で、めったに使用されず、ほとんどの場合に予期しない結果をもたらすため、Swift 4で削除されました。
編集:OOPerが指摘したように、この機能はSwift 4ベータ版で一時的に削除されましたが、最終バージョンが公開される前に再度追加する必要があります。

代わりに、あなたは書くべきです:

try flatMap({ tupleArgument in
    return try transform(tupleArgument.key, tupleArgument.value)
})

そして、flatMap関数は次のようになります。

func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] {
    return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ element in
        return try transform(element.key, element.value)
    }))
}
24
deadbeef

Swift 4:に対するこの提案の副作用です。

SE-0110単一タプルと複数引数の関数タイプを区別する

しかし、この提案に含まれるいくつかの機能は、いくつかの回帰を引き起こしました。これは evolution-announceメーリングリスト のこの投稿で対処されています

[Swift-evolution-announce] [Core team] Swift 4 のSE-0110ユーザビリティ回帰に対処

したがって、将来のベータ版またはGM Xcode 9のバージョンでは、コードは再びコンパイルされるでしょう。それまでは、この種の回避策を使用できます。

internal func flatMap<KeyPrime , ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime : ValuePrime] {
    return Dictionary<KeyPrime,ValuePrime>(elements: try flatMap({ pair in
        let (key, value) = pair
        return try transform(key, value)
    }))
}

ちなみに、Swift 4、Dictionaryには、Sequence(Key, Value)ペア。例えば:

init(uniqueKeysWithValues:S)

7
OOPer

enumerated().map()を使用した結果、このエラーが発生しました。

クロージャータプルパラメーターは、構造化をサポートしていません

私はコードを入力しました:

["foo"].enumerated().map(

そして押し続けた Enter Xcodeがクロージャボイラープレートをオートコンプリートするまで。

オートコンプリートには、上記のエラーを引き起こすバグがあるようです。オートコンプリートは、単一括弧((offset: Int, element: String))ではなく二重括弧(offset: Int, element: String)を生成します。

私はそれを手動で修正し、続行することができました:

// Xcode autocomplete suggests:
let fail = ["foo"].enumerated().map { ((offset: Int, element: String)) -> String in
    return "ERROR: Closure Tuple parameter does not support destructuring"
}

// Works if you manually replace the "(( _ ))" with "( _ )"
let pass = ["foo"].enumerated().map { (offset: Int, element: String) -> String in
    return "works"
}

おそらくXcode 10.0ベータ(10L176w)を使用した結果

3
pkamb