मैं कोटलिन में जेनेरिक प्रकार की जांच कैसे कर सकता हूं


84

मैं कोटलिन में एक सामान्य प्रकार के लिए परीक्षण करने की कोशिश कर रहा हूं।

if (value is Map<String, Any>) { ... }

लेकिन कंपाइलर से शिकायत है

मिटाए गए प्रकार के उदाहरण के लिए जाँच नहीं कर सकते हैं: जेट

एक सामान्य प्रकार के साथ चेक अच्छी तरह से काम करता है।

if (value is String) { ... }

कोटलिन 0.4.68 का उपयोग किया जाता है।

मुझे यहां क्या समझ नहीं आ रहा है?

जवाबों:


92

समस्या यह है कि प्रकार के तर्क मिटा दिए जाते हैं, इसलिए आप पूर्ण प्रकार के मानचित्र के खिलाफ जांच नहीं कर सकते, क्योंकि रनटाइम पर उन स्ट्रिंग और किसी के बारे में कोई जानकारी नहीं है।

इसके आसपास काम करने के लिए, वाइल्डकार्ड का उपयोग करें:

if (value is Map<*, *>) {...}

महान! यह पूरी तरह से काम करता है! मैं सिर्फ प्रलेखन में उदाहरण द्वारा भ्रमित हो गया: confluence.jetbrains.net/display/Kotlin/Type+casts
फिलिप ब्रूएल

51
क्या होगा यदि आप वास्तव में यह जांचना चाहते हैं कि कुछ Collection<String>इसे ऑटो कास्ट बनाने के लिए है?
बेरिक

मेरे पास इस तरह स्निपेट है if (it.getSerializable(ARG_PARAMS) is HashMap<*, *>) {it.getSerializable(ARG_PARAMS) as HashMap<String, String>} else null। अगर मैं सामान्य प्रकार के खिलाफ जांच कर रहा हूं तो मूल रूप से यह कास्ट HashMap<String, Integer>करने का प्रयास करने वाला HashMap<String, String>हूं। क्या मैं कुछ भूल रहा हूँ?
फरीद

@FARID हां, यह होगा, और इस तरह की कास्ट सुरक्षित नहीं है
एंड्री ब्रेस्लेव

18

जेवीएम जेनेरिक प्रकार की जानकारी को हटा देता है। लेकिन कोटलिन ने जेनेरिक को फिर से परिभाषित किया है। यदि आपके पास जेनेरिक टाइप टी है, तो आप इनलाइन फ़ंक्शन के प्रकार पैरामीटर टी को पुन: अंकित कर सकते हैं ताकि यह रनटाइम पर जांच कर सके।

तो आप कर सकते हैं:

inline fun <reified T> checkType(obj: Object, contract: T) {
  if (obj is T) {
    // object implements the contract type T
  }
}

3
क्या आप कॉल करने का एक उदाहरण दिखा सकते हैं checkType()? मुझे यकीन नहीं है कि दूसरे तर्क के लिए क्या करना है।
बजे माइकल ओसोफस्की

10

मुझे लगता है कि यह अधिक उपयुक्त तरीका है

inline fun <reified T> tryCast(instance: Any?, block: T.() -> Unit) {
    if (instance is T) {
        block(instance)
    }
}

प्रयोग

// myVar is nullable
tryCast<MyType>(myVar) {
    // todo with this e.g.
    this.canDoSomething()
}

एक और छोटा दृष्टिकोण

inline fun <reified T> Any?.tryCast(block: T.() -> Unit) {
    if (this is T) {
        block()
    }
}

प्रयोग

// myVar is nullable
myVar.tryCast<MyType> {
    // todo with this e.g.
    this.canDoSomething()
}

1
क्यों ऐसा कुछ सीधे कोटलिन stdlib में उपलब्ध नहीं है :-(
ATom

something as? Stringएक ही नहीं है? प्रश्न चिह्न के बाद नोट करें as?
Dalibor Filus

@ डेलिबोरफिलस नप। यह रनटाइम के दौरान जेनरिक और मिटाए गए प्रकारों के बारे में है। यदि आपको जेनेरिक से निपटना नहीं है, तो आप बस as?सही, उपयोग कर सकते हैं ।
stk

0

मैंने उपरोक्त समाधान की कोशिश की है tryCast<Array<String?>>और मुझे लगता है कि कई कास्टिंग के साथ लिस्टिंग में अपने विशिष्ट कार्य में यह इतना बड़ा विचार नहीं था, क्योंकि यह प्रदर्शन को काफी धीमा कर रहा था।

यह वह समाधान है जो मैंने अंततः किया था - प्रविष्टियों और कॉल विधियों की मैन्युअल रूप से जाँच करें, जैसे:

 fun foo() {
    val map: Map<String?, Any?> = mapOf()
    map.forEach { entry ->
        when (entry.value) {
            is String -> {
                doSomeWork(entry.key, entry.value as String)
            }
            is Array<*> -> {
                doSomeWork(entry.key, (entry.value as? Array<*>)?.map {
                    if (it is String) {
                        it
                    } else null
                }?.toList())
            }
        }
    }
}


private fun doSomeWork(key: String?, value: String) {

}
private fun doSomeWork(key: String?, values: List<String?>?) {

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.