2015-06-18 10 views
15

में टाइप वेरिएबल का उपयोग करना मेरे पास स्विफ्ट को छोड़कर this question है। मैं एक सामान्य में Type चर का उपयोग कैसे करूं?जेनेरिक

मैं इस कोशिश की:

func intType() -> Int.Type { 
    return Int.self 
} 

func test() { 
    var t = self.intType() 
    var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is. 
} 

यह या तो काम नहीं किया:

var arr = Array<t.Type>() // Error: "'t' is not a type" 
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all. 

वहाँ यह करने के लिए कोई तरीका है? मुझे यह महसूस हो रहा है कि स्विफ्ट सिर्फ इसका समर्थन नहीं करता है और मुझे कुछ हद तक संदिग्ध त्रुटि संदेश दे रहा है।

संपादित करें: यहां एक और जटिल उदाहरण है जहां समस्या को सामान्य फ़ंक्शन हेडर का उपयोग करके अवरुद्ध नहीं किया जा सकता है। बेशक यह मतलब नहीं है, लेकिन मैं अपने कोड में कहीं कार्यक्षमता के इस प्रकार के लिए एक समझदार उपयोग किया है और नहीं बल्कि अपने वास्तविक कोड के बजाय एक स्वच्छ उदाहरण पोस्ट होगा:

func someTypes() -> [Any.Type] { 
    var ret = [Any.Type]() 
    for (var i = 0; i<rand()%10; i++) { 
     if (rand()%2 == 0){ ret.append(Int.self) } 
     else {ret.append(String.self) } 
    } 
    return ret 
} 

func test() { 
    var ts = self.someTypes() 

    for t in ts { 
     var arr = Array<t>() 
    } 
} 

उत्तर

22

स्विफ्ट का static typing का मतलब है कि एक चर का प्रकार संकलन समय पर जाना जाना चाहिए।

एक सामान्य समारोह func foo<T>() { ... }, टी के संदर्भ में एक चर की तरह लग रहा है, लेकिन इसकी प्रकार वास्तव में पर जहां समारोह से कहा जाता है आधारित संकलन समय पर जाना जाता है। Array<T>() का व्यवहार T पर निर्भर करता है, लेकिन यह जानकारी संकलन समय पर ज्ञात है।

प्रोटोकॉल का उपयोग करते हैं, तो आप स्विफ्ट Array<MyProtocol>() लिख सकते हैं, गतिशील प्रेषण कार्यरत हैं, और सरणी बस बातें जो MyProtocol को लागू करने के संदर्भ संग्रहीत करती है - तो जब आप सरणी से कुछ मिलता है, आप सभी कार्यों के लिए उपयोग किया/MyProtocol द्वारा आवश्यक चर/टाइपलाइसेस।

लेकिन अगर t वास्तव में तरह Any.Type के चर है, Array<t>() व्यर्थ है के बाद से अपनी तरह वास्तव में संकलन समय पर ज्ञात नहीं है। (चूंकि Array एक सामान्य संरचना है, इसलिए संकलक को सामान्य पैरामीटर के रूप में उपयोग करने के लिए किस प्रकार की आवश्यकता है, लेकिन यह संभव नहीं है।)

मैं इस साल WWDC से कुछ वीडियो देखने की सलाह देते हैं:

मैं इस स्लाइड प्रोटोकॉल और गतिशील प्रेषण को समझने के लिए विशेष रूप से उपयोगी पाया:

+0

एमएमएम, तो यह समस्या का दिल है। मुझे लगता है कि मुझे तब उन वीडियो देखना चाहिए! – sudo

4

एक तरीका होता है और यह है जेनेरिक कहा जाता है। आप ऐसा कुछ कर सकते हैं।

class func foo() { 
    test(Int.self) 
} 

class func test<T>(t: T.Type) { 
    var arr = Array<T>() 
} 

आप प्रकार आप, साथ एक तरह से या किसी अन्य समारोह के विशेषज्ञ करना चाहते हैं पर संकलक संकेत की जरूरत होगी।

class func foo() { 
    let _:Int = test() 
} 

class func test<T>() -> T { 
    var arr = Array<T>() 
} 

और जेनरिक का उपयोग कर एक वर्ग (या struct) पर आप अतिरिक्त परम की जरूरत नहीं है:

class Whatever<T> { 
    var array = [T]() // another way to init the array. 
} 

let we = Whatever<Int>() 
+0

गु: पता हो सकता है, तो आप वैकल्पिक रूप से arr[Any] के रूप में प्रकार ("heterogenous" jtbandes 'जवाब में मामले) मिश्रण करने की घोषणा कर सकता है मेरा उदाहरण ठीक करेगा, लेकिन यह सामान्य रूप से काम नहीं करता है। क्या होगा यदि आपके पास एक प्रकार का चर-आकार सरणी है जिसमें आप पास करना चाहते हैं? मेरे पास वास्तव में यह है, लेकिन मैं एक साधारण उदाहरण पोस्ट करना चाहता था। मैं एक उदाहरण जोड़ूंगा जहां जेनेरिक काम नहीं करेगा। – sudo

+0

हालांकि अभी भी एक अच्छा जवाब है। इस मामले में यह सहायक है कि मैं संकलन समय के दौरान पर्याप्त जानता हूं। लेकिन मैं नेटवर्क कनेक्शन पर प्रकार प्राप्त कर रहा हूं और उनसे ऑब्जेक्ट्स बनाने की कोशिश कर रहा हूं, इसलिए मैं पूरी तरह से सामान्य समाधान की तलाश में हूं। – sudo

2

मैं इसे टूट जाएगा एक और तरीका है वापसी परम (उस मामले में खारिज कर दिया) के साथ है उन चीज़ों के साथ नीचे जो आपने पहले जवाब से पहले ही सीखा है। मैंने कुछ कोड रिफैक्टर करने की स्वतंत्रता ली। यहां यह है:

func someTypes<T>(t: T.Type) -> [Any.Type] { 
    var ret = [Any.Type]() 
    for _ in 0..<rand()%10 { 
     if (rand()%2 == 0){ ret.append(T.self) } 
     else { 
      ret.append(String.self) 
     } 
    } 
    return ret 
} 


func makeArray<T>(t: T) -> [T] { 
    return [T]() 
} 

func test() { 
    let ts = someTypes(Int.self) 
    for t in ts { 
     print(t) 
    } 
} 

यह कुछ हद तक काम कर रहा है लेकिन मेरा मानना ​​है कि ऐसा करने का तरीका बहुत अपरंपरागत है। क्या आप इसके बजाय प्रतिबिंब (मिररिंग) का उपयोग कर सकते हैं?

+0

यह दिलचस्प और रचनात्मक है, लेकिन मुझे नहीं लगता कि यह प्रयोग योग्य है। मान लें कि 'लूप के लिए' test() '' '' 'var arr = makeArray (t)' जोड़ें। 'arr' प्रकार 'Array प्रकार होगा। टाइप करें,', जिसे किसी भी चीज़ पर नहीं डाला जा सकता है। –

+0

आश्चर्यजनक रूप से, यह विफल रहता है जब भी मैं 'Int.self' के बजाय वहां कुछ गतिशील रखने की कोशिश करता हूं। इस तरह: 'var type: Any.Type; अगर (रैंड()% 2 == 0) {type = Int.self}; अन्य {type = String.self}; टीएस = कुछ प्रकार (प्रकार); ' – sudo

+1

और मुझे इसके लिए प्राप्त होने वाले त्रुटि संदेशों को पसंद नहीं है। ऐसा लगता है जैसे स्विफ्ट नियमों को बना रहा है। – sudo

4

jtbandes का उत्तर - कि आप अपने वर्तमान दृष्टिकोण का उपयोग नहीं कर सकते क्योंकि स्विफ्ट स्थिर रूप से टाइप किया गया है - सही है।

हालांकि, यदि आप अपने सरणी में स्वीकार्य प्रकारों का श्वेतसूची बनाने के इच्छुक हैं, उदाहरण के लिए enum में, आप रनटाइम पर विभिन्न प्रकारों को गतिशील रूप से प्रारंभ कर सकते हैं।

पहले, स्वीकार्य प्रकार के enum बनाएँ:

enum Types { 
    case Int 
    case String 
} 

एक Example वर्ग बनाएँ। इन enum मानों का उपयोग करने के लिए अपने someTypes() फ़ंक्शन को कार्यान्वित करें। गुंजाइश arr करने के लिए प्रत्येक स्वीकार्य प्रकार के लिए (आप आसानी से तार का एक JSON सारणी इस enum की एक सरणी के रूप में बदल सकता है।)

class Example { 
    func someTypes() -> [Types] { 
     var ret = [Types]() 
     for _ in 1...rand()%10 { 
      if (rand()%2 == 0){ ret.append(.Int) } 
      else {ret.append(.String) } 
     } 
     return ret 
    } 

अब आप अपने परीक्षण समारोह को लागू, switch का उपयोग कर:

func test() { 
     let types = self.someTypes() 

     for type in types { 
      switch type { 
      case .Int: 
       var arr = [Int]() 
       arr += [4] 

      case .String: 
       var arr = [String]() 
       arr += ["hi"] 
      } 
     } 
    } 
} 

आप के रूप में

var arr = [Any]() 

for type in types { 
    switch type { 
    case .Int: 
     arr += [4] 

    case .String: 
     arr += ["hi"] 
    } 
} 

print(arr) 
संबंधित मुद्दे