web-dev-qa-db-ja.com

Array.map()は予期されるコンテキスト結果タイプ '[String:Any?]'ではなく '[T]'を生成します

FirebaseDatabaseと Eureka の間で辞書の値をブリッジする拡張機能を書いています。

private extension Dictionary {
    func firebaseFriendlyDictionary() -> [String: Any?] {
        return self.map({ (key: String, value: Any?) -> (String, Any?) in
            if value is NSDate {
                return (key, (value as! NSDate).timeIntervalSince1970)
            }
            return (key, value)
        })
    }
}

しかし、ビルドしようとするとこのエラーがスローされます:

map produces '[T]', not the expected contextual result type '[String: Any?]'

15
Liau Jian Jie

あなたの問題は、mapArrayに適用された場合でも、常にDictionaryを返すという事実にあります。エラーメッセージは基本的に、Dicitonaryを返すようにメソッドを宣言したが、内部のステートメントはArray[T]-someタイプTのオブジェクトを持つ配列を意味します。あなたの場合、mapによって返される配列にはtuplesが含まれます(詳細については here )。この場合、キーと値のペアのように見えますが、ディクショナリ内のキーと値のペアとは異なります。基本的に、タプルを使用すると、メソッドから複数の値/オブジェクトを返すことができます。それらはanonymous構造と考えることができます。

私の意見では、必要なことを達成するためにmapを使用する必要はありません。Xcoder氏が提供するソリューションはその方法です。

6
Losiowaty

mapのような機能的な関数を本当に使用したい場合、実際に必要なメソッドはreduceです。

実演します。できる限り明確にするために、私はあなたの値が受けている変換をそれ自身の関数に分離することは助けになると思います:

func dateToSeconds(_ thing:Any?) -> Any? {
    guard let date = thing as? Date else {return thing}
    return date.timeIntervalSince1970
}

さて、ここに私たちのテスト辞書があります:

let d1 : [String:Any?] = ["1":Date(), "2":"two", "3":15, "4":true]

これでreduceを適用する準備ができました。 2つのパラメーターを関数に渡します。 1つ目は、「アキュムレータ」で、最終的な結果を構築し続けます。この場合は、別の辞書です。 2番目は、元のディクショナリの要素であり、keyおよびvalueと呼ばれるキーと値のペアのTupleとして表されます。

let d2 = d1.reduce([String:Any?]()) { (dict, Tuple) in
    var dict = dict
    dict[Tuple.key] = dateToSeconds(Tuple.value)
    return dict
}

そして、d2、正しい答えが得られたことがわかります。

d2 // ["3": {some 15}, "2": {some "two"}, "1": {some 1486228695.557882}, "4": {some true}]
6
matt

私はそのエラーを修正する方法を理解できませんでした。また、拡張機能またはmap()で目的の結果を達成することはできませんでしたが、関数

辞書の宣言:

var date = NSDate()
var swiftDict:[String : Any?] = ["1":  date, "2": "two", "3": 15, "4": true]

機能:

func firebaseFriendlyDictionary(_ dict: [String : Any?]) -> [String : Any?]{
    var Dict = dict
    for (key, value) in dict
    {
        if (value is NSDate){
            Dict[key] = (value as! NSDate).timeIntervalSince1970
        }
    }
    return Dict
}

用途:

swiftDict = firebaseFriendlyDictionary(swiftDict)

テスト:

日付があるとします2017-02-04 16:42:46 +0000出力は1486226566.2349629、 どちらが正しい。

辞書をマッピングしないのはなぜですか?AsLosiowaty彼の優れた答えで指摘したように、mapは常にArrayを返します。この場合、ArrayTuples[T])。私の考えでは、このコンテキストではマップ関数は必要ありません。さらに、実行するにはさらに多くのコードが必要です。

お役に立てれば!

4
Mr. Xcoder