2017-12-25 119 views
6

मैं उच्च आदेश कार्यों के लिए .lazy की जांच की गई थी और समारोह (और संभवतः दूसरों)एक अर्थहीन अभिव्यक्ति के साथ flatMap में "वापसी अभिव्यक्ति कनवर्ट नहीं कर सकता"

उदाहरण flatMap से संबंधित कुछ रोचक संकलन त्रुटियों मिल गया है अंदर

 
let array = [1, 2, 3, 4, 5, 6] 

array 
    .flatMap { 
     print("DD") 
     return $0 // Cannot convert return expression of type 'Int' to return type 'String?' 
    } 
    .forEach { 
     print("SS") 
     print($0) 
} 

थोड़ा

 
array 
    .flatMap { 
//  print("DD") 
     return $0 
    } 
    .forEach { 
     print("SS") 
     print($0) 
} 
बाहर टिप्पणी करते हुए

और सब कुछ काम करता है .. और भी दिलचस्प उदाहरण

 
array 
    .flatMap { 
     let z = $0 
     return $0 // Or return z - all is the same "Cannot convert return expression of type 'Int' to return type 'String?'" 
    } 
    .forEach { 
     print("SS") 
     print($0) 
} 

क्या है कि व्यवहार का कारण बन सकता है?

उत्तर

4

flatMap(_:) (स्विफ्ट 4) के रूप में Sequence वर्तमान में विधि दो अलग अलग अर्थ है:

  • यह एक बंद है कि एक वैकल्पिक T? रिटर्न को बदलने का समय लग सकता है, और यह वापस आ जाएगी [T], nil परिणामों को फ़िल्टर करना (भविष्य में संस्करण में यह अधिभार is to be renamedcompactMap(_:))।

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

  • यह एक बंद है कि एक Sequence रिटर्न को बदलने का समय लग सकता है, और यह सभी परिणामी दृश्यों के संयोजन से युक्त एक सरणी वापस आ जाएगी।

    public func flatMap<SegmentOfResult : Sequence>(
        _ transform: (Element) throws -> SegmentOfResult 
    ) rethrows -> [SegmentOfResult.Element]

अब, स्विफ्ट 4 में, String बन गया एक RangeReplaceableCollection (और इसलिए एक Sequence)।तो स्विफ्ट 3 कोड है कि ऐसा किया:

// returns ["foo"], as using the `nil` filtering flatMap, the elements in the closure 
// are implicitly promoted to optional strings. 
["foo"].flatMap { $0 } 

अब यह करता है:

//===----------------------------------------------------------------------===// 
// The following overloads of flatMap are carefully crafted to allow the code 
// like the following: 
// ["hello"].flatMap { $0 } 
// return an array of strings without any type context in Swift 3 mode, at the 
// same time allowing the following code snippet to compile: 
// [0, 1].flatMap { x in 
//  if String(x) == "foo" { return "bar" } else { return nil } 
// } 
// Note that the second overload is declared on a more specific protocol. 
// See: test/stdlib/StringFlatMap.swift for tests. 
extension Sequence { 
    @_inlineable // FIXME(sil-serialize-all) 
    @available(swift, obsoleted: 4) 
    public func flatMap(
    _ transform: (Element) throws -> String 
) rethrows -> [String] { 
    return try map(transform) 
    } 
} 

extension Collection { 
    @_inlineable // FIXME(sil-serialize-all) 
    public func flatMap(
    _ transform: (Element) throws -> String? 
) rethrows -> [String] { 
    return try _flatMap(transform) 
    } 
} 

इस तरह की:

// returns ["f", "o", "o"], a [Character], as using the Sequence concatenation flatMap, 
// as String is now a Sequence (compiler favours this overload as it avoids the implicit 
// conversion from String to String?) 
["foo"].flatMap { $0 } 

स्रोत अनुकूलता की रक्षा करने के लिए, flatMap भार के तार के लिए were added विशेष कि उपर्युक्त उपयोग अभी भीलौटाएगा स्विफ्ट 3 संगतता मोड में, लेकिन स्विफ्ट 4.

में एक [Character] तो, क्यों

let array = [1, 2, 3, 4, 5, 6] 

array 
    .flatMap { 
     print("DD") 
     return $0 // Cannot convert return expression of type 'Int' to return type 'String?' 
    } 
    .forEach { 
     print("SS") 
     print($0) 
    } 

आपको बता दूँ कि बंद एक String? लौट जाना पड़ता है?

खैर, स्विफ्ट वर्तमान में पैरामीटर प्राप्त करेगा और बहु ​​बयान बंद के लिए प्रकार (अधिक जानकारी के लिए this Q&A देखें) वापस नहीं करता है। तो flatMap(_:) भार के जहां बंद रिटर्न या तो एक सामान्य T? या एक सामान्य S : Sequence पात्र नहीं हैं, स्पष्ट प्रकार एनोटेशन बिना कहे जाने के रूप में वे प्रकार निष्कर्ष की आवश्यकता होती है सामान्य प्लेसहोल्डर को पूरा करने के हैं।

इस प्रकार, योग्यता वाला एकमात्र अधिभार विशेष String स्रोत संगतता एक है, इसलिए संकलक String? लौटने के बंद होने की उम्मीद कर रहा है।

array 
    .flatMap { i -> Int? in 
    print("DD") 
    return i 
    } 
    .forEach { 
    print("SS") 
    print($0) 
    } 

लेकिन अगर आप वास्तव में अपने वास्तविक कोड में इस flatMap(_:) अधिभार की वैकल्पिक छानने कार्यक्षमता का उपयोग नहीं कर रहे हैं, तो आप का उपयोग करना चाहिए:

इसे ठीक करने के आप स्पष्ट रूप से बंद होने की वापसी प्रकार टिप्पणी कर सकते हैं इसके बजाय map(_:)

+1

ग्रेट उत्तर, धन्यवाद! मैं वास्तविक कोड में 'flatMap (_ :)' की वैकल्पिक फ़िल्टरिंग कार्यक्षमता का उपयोग कर रहा था। मैंने मुद्दे को दिखाने के लिए कुछ कोड छीन लिया है बिना मुद्दों के बारीकी से संबंधित। –

4

flatMap संदर्भ के आधार पर अलग-अलग अर्थ हो सकते हैं। आप संकलक को अधिक सटीक बता सकते हैं कि आप किस का उपयोग करना चाहते हैं।

enter image description here


दो सामान्य प्रयोजनों के एक सरणी जो संकलक अनुमान लगा सकते हैं

  • है करने के लिए flatMap लागू करने के लिए समतल नेस्टेड सरणियों

    let array = [[1, 2, 3, 4, 5, 6], [7, 8, 9]] 
    let flattened = array.flatMap{$0} 
    print(flattened) // [1, 2, 3, 4, 5, 6, 7, 8, 9] 
    
  • दूसरे करने के लिए मानचित्र प्रकार और फ़िल्टर विकल्प

    let array = ["1", "a", "2", "3", "b", "4", "5", "6"] 
    let flattened = array.flatMap{ Int($0) } 
    print(flattened) // [1, 2, 3, 4, 5, 6] 
    
+0

हाँ, मुझे लगता है कि निर्दिष्ट करने के बारे और बाद मैं अभी-अभी जोड़ा '(संख्या) नहीं लगता था -> इंट? में सबकुछ अपेक्षित काम करता है। धन्यवाद :) –

संबंधित मुद्दे