2015-10-30 13 views
11

में सामान्य मापदंडों के कमी जोड़े मैं इस समारोह है:विस्तार

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] एक (वैकल्पिक) के बिना।

मैं केवल वर्ग है जो मूल्य किसी भी प्रकार की एक Optional है के लिए एक नया विधि के साथ Dictionary वर्ग का विस्तार करना चाहता था, लेकिन मैं शब्दकोश का जेनेरिक मानकों को बाधाओं को जोड़ने में असमर्थ हूँ।

यह है कि मैं क्या करने की कोशिश की है:

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

लेकिन त्रुटि के साथ विफल: क्योंकि जब आप एकदम सही प्रकार निर्दिष्ट नहीं कर सकते

// 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"] 

:

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

उत्तर

16

खेल का मैदान में इस कोड का प्रयास करें प्रोटोकॉल एक्सटेंशन के where खंड में, एक तरह से आप वास्तव मेंका पता लगा सकते हैंप्रकार Optional बनाने के लिए एक प्रोटोकॉल के अनुरूप है (OptionalEquivalent कहें)।

आदेश Optional की लिपटे मान प्रकार पाने के लिए, मैं कस्टम प्रोटोकॉल OptionalEquivalent में एक typealias WrappedValueType परिभाषित और फिर वैकल्पिक का ही विस्तार किया, Wrapped को WrappedValueType assgin, तो आप समतल विधि में प्रकार प्राप्त कर सकते हैं ।

ध्यान दें कि sugarCast विधि बस (जो बिल्कुल वही बात है) Optional<Wrapped>Wrapped? को कास्ट करने के लिए है उपयोग guard बयान सक्षम करने के लिए।

अद्यतन

रोब नेपियर की टिप्पणी का धन्यवाद मैं सरलीकृत & नाम दिया sugarCast() विधि और प्रोटोकॉल इसे और अधिक समझ में आता है बनाने के लिए नाम दिया।

+0

आप कर सकते हैं 'चीनी वापसी()' को 'वापसी स्वयं' के रूप में लागू करें। मैं व्यक्तिगत रूप से इस प्रोटोकॉल 'वैकल्पिक कन्वर्टिबल' और 'चीनीकास्ट() '' toOptional() 'को कॉल करने की सलाह देता हूं, लेकिन आपका तरीका भी ठीक है। –

+0

आप सही हैं, मैं अपना कोड – cezheng

+0

अपडेट करूंगा जो सामान्य सीमाओं को हल करने का एक बहुत ही रचनात्मक तरीका है। मैं शायद इसे और अधिक स्थानों में उपयोग करूंगा। धन्यवाद – redent84

2

आप इसे सरल तरीके से कर सकते हैं। यह स्विफ्ट 4 के साथ काम करता है:

extension Dictionary { 
    func flatten<Wrapped>() -> [Key: Wrapped] where Value == Optional<Wrapped> { 
     return filter { $1 != nil }.mapValues { $0! } 
    } 
} 

आप उच्च आदेश कार्यों का उपयोग पसंद नहीं है या स्विफ्ट के पिछले संस्करणों के साथ संगतता की जरूरत है तो आप इस रूप में अच्छी तरह कर सकते हैं: और अधिक आसानी से

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

स्वीकृत उत्तर से अधिक आसान और पठनीय – moskis

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