2016-02-16 36 views
7

में काम नहीं कर रहा है प्रोटोकॉल प्रिंट करने योग्य और तृतीय पक्ष से एक स्ट्रक्चर प्रिंटर है।जेनेरिक विधि ओवरराइड स्विफ्ट

protocol Printable {} 

struct Printer { 

    static func print<T>(object: T) -> String { 
     return "T" 
    } 

    static func print<T: Printable>(object: T) -> String { 
     return "Printable" 
    } 

} 

अब मैं एक सामान्य

struct Generic<T> { 

    var args: T 

    func display() { 
     print(Printer.print(args)) 
    } 

} 

और दो structs

struct Obj {} 
struct PrintableObj: Printable {} 
var obj = Generic(args: Obj()) 
var printableObj = Generic(args: PrintableObj()) 

बनाने रहा हूँ जब मैं उन दोनों पर प्रदर्शन कार्यों कहते हैं।

obj.display() 

प्रदर्शित करता है टी

printableObj.display() 

प्रदर्शित करता है टी, लेकिन मैं यह "मुद्रण योग्य"

एक समाधान मैं के बारे में सोच सकते हैं चल रहा है प्रिंट करना चाहते हैं दो अलग अलग जेनरिक

struct Generic<T> 
struct PrintableGeneric<T: Printable> 

प्रिंट करने योग्य पी को बदलने के बिना कोई अन्य समाधान है रोटोकॉल और प्रिंटर संरचना।

उत्तर

1

हां। लेकिन जवाब थोड़ा अजीब है। पहला भाग समझदार सभ्यता बनाता है; दूसरा हिस्सा सिर्फ पूरी तरह से अजीब है। चलो इसके माध्यम से चलते हैं।

struct Generic<T> { 
    var args: T 
    func display() { 
     print(Printer.print(args)) 
    } 
} 

सही अधिभार print के लिए चयन करने के लिए संकलन समय पर निर्णय लिया जाता है, रनटाइम नहीं। यह वह चीज है जो लोगों को सबसे ज्यादा भ्रमित करती है। वे स्विफ्ट को जावास्क्रिप्ट की तरह व्यवहार करना चाहते हैं जहां सब कुछ गतिशील है। स्विफ्ट स्थिर होना पसंद करता है क्योंकि तब यह सुनिश्चित कर सकता है कि आपके प्रकार सही हैं और यह कई अनुकूलन कर सकता है (और स्विफ्ट संकलक अनुकूलन करने के लिए से प्यार करता है)। तो, समय संकलित करें, args किस प्रकार का है? खैर, यह T है। TPrintable होने के लिए जाना जाता है? नहीं ऐसा नहीं है। तो यह गैर-Printable संस्करण का उपयोग करता है।

लेकिन स्विफ्ट GenericPrintableObj का उपयोग करके माहिर हैं, क्या यह उस बिंदु पर नहीं जानता है कि यह Printable है? संकलक उस बिंदु पर display का एक अलग संस्करण नहीं बना सका? हां, अगर हम संकलित समय में प्रत्येक कॉलर को जानते थे जो कि इस समारोह के अस्तित्व में होगा, और उनमें से कोई भी कभी भी Printable (जो कि पूरी तरह से अलग मॉड्यूल में हो सकता है) तक बढ़ाया जाएगा। बहुत सारे अजीब कोने के मामलों (जहां आंतरिक चीजें उदाहरण के लिए सार्वजनिक चीजों की तुलना में अलग-अलग व्यवहार करती हैं) के बिना इसे सुलझाना मुश्किल है, और बिना किसी भविष्य के कॉलर द्वारा display के हर संभव संस्करण को सक्रिय रूप से उत्पन्न करने के लिए स्विफ्ट को मजबूर किए बिना। समय में स्विफ्ट में सुधार हो सकता है, लेकिन मुझे लगता है कि यह एक कठिन समस्या है। (स्विफ्ट को पहले से ही कुछ प्रदर्शन में कमी का सामना करना पड़ता है ताकि सार्वजनिक जेनेरिक को मूल स्रोत कोड तक पहुंच के बिना विशेषीकृत किया जा सके। इससे यह समस्या और भी जटिल हो जाएगी।)

ठीक है, तो हम इसे प्राप्त करते हैं। TPrintable नहीं है। लेकिन क्या होगा यदि हमारे पास एक प्रकार था जो अनजाने में Printable था जिसे हम संकलित समय में जानते थे और इस समारोह के अंदर रहते थे? क्या यह तब काम करेगा?

func display() { 
    if let p = args as? Printable { 
     print(Printer.print(p)) 
    } else { 
     print(Printer.print(args)) 
    } 
} 

ओह बहुत करीब ... लेकिन काफी नहीं। यह लगभग काम करता है। if-let वास्तव में वही करता है जो आप करना चाहते हैं। p असाइन किया जाता है। यह Printable है। लेकिन यह अभी भी गैर-प्रिंट करने योग्य फ़ंक्शन को कॉल करता है। ?!?!?!?!

यह एक ऐसा स्थान है जहां मैं व्यक्तिगत रूप से सोचता हूं कि स्विफ्ट वर्तमान में टूटा हुआ है और इसकी उम्मीद है कि इसे ठीक किया जाएगा। यह एक बग भी हो सकता है। समस्या यह है कि Printable स्वयं Printable के अनुरूप नहीं है। हाँ, मुझे यह नहीं मिला है, लेकिन आप वहां जाते हैं। इसलिए हमें कुछ ऐसा करने की ज़रूरत है जो सही अधिभार प्राप्त करने के लिए Printable के अनुरूप है। सामान्य रूप से, बचाव के लिए type erasers

struct AnyPrintable: Printable { 
    let value: Printable 
} 

struct Generic<T> { 
    var args: T 

    func display() { 
     if let p = args as? Printable { 
      print(Printer.print(AnyPrintable(value: p))) 
     } else { 
      print(Printer.print(args)) 
     } 
    } 
} 

और यह आपके इच्छित तरीके से प्रिंट करेगा। (इस धारणा है कि Printable कुछ तरीकों की आवश्यकता है पर, आप सिर्फ AnyPrintable प्रकार रबड़ के लिए उन तरीकों को जोड़ने चाहते हैं।)

बेशक

सही जवाब Printer में जेनेरिक भार के इस तरह से उपयोग करने के लिए नहीं है। यह बहुत ही भ्रमित और नाजुक तरीका है। यह बहुत अच्छा लग रहा है, लेकिन यह हर समय उड़ाता है।

+0

इस जानकारी के लिए आपको बहुत बहुत धन्यवाद। यह ठीक करने के लिए जटिल लग रहा है कि मैं अभी क्या करने की कोशिश कर रहा हूं। https://github.com/RahulKatariya/Reactofire/blob/develop/ReactofireTests/Models/GenericResponse/_GenericResponse.swift .. मैं जेनेरिक रेस्पॉन्सस्ट्रिंग और जेनेरिक रीस्पॉन्सपर्सन परीक्षण पास करने की कोशिश कर रहा हूं। –

+0

शुभकामनाएं ... मैंने बुनियादी समस्याओं के लिए इस तरह के सुपर-चालाक/जादुई दृष्टिकोणों में बहुत सारे प्रयोग किए। व्यक्तिगत रूप से मैंने पाया कि सरल कोड की कुछ पंक्तियां, भले ही आपको कभी-कभी कुछ कठिन लाइनों को दोहराना पड़ता है, फिर भी बेहतर काम करता है, खासकर जब यह डीबग करने का समय होता है (मैं अभी अपने JSON पार्सिंग को 'गार्ड-लेट' करता हूं; इतना आसान)। यह उतना रोमांचक नहीं है, लेकिन यह मेरी परियोजनाओं में बहुत बेहतर काम करता है। लेकिन उन लोगों के लिए शुभकामनाएं जो अभी भी सीमा की खोज कर रहे हैं! यह मजेदार है, लेकिन इस तरह की बहुत निराशा होती है। –

1

मेरे मन के लिए, एक ही विकल्प आपके पास - अगर-किसी और समारोह

static func print<T>(object: T) -> String { 
    if let _ = object as? Printable { 
     return "Printable" 
    } 
    return "T" 
} 

या गैर जेनेरिक संस्करण

static func print(object: Any) -> String { 
    if let _ = object as? Printable { 
     return "Printable" 
    } 
    return "T" 
} 
+0

धन्यवाद। लेकिन वह कोड किसी अन्य स्रोत से है और मैं इसे संशोधित नहीं कर सकता। मैं जेनेरिक में केवल बदलाव कर सकता हूं। –

2
static func print<T>(object: T) -> String { 
    if object is Printable { 
     return "Printable" 
    } else { 
     return "T" 
    } 
} 
में टाइप कास्टिंग के साथ उपयोग करने के लिए "प्रिंट()" है
+0

धन्यवाद। लेकिन वह कोड किसी अन्य स्रोत से है और मैं इसे संशोधित नहीं कर सकता। मैं जेनेरिक में केवल बदलाव कर सकता हूं। –

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