कोटलिन: सूची कलाकारों के साथ कैसे काम करें: अनियंत्रित कास्ट: kotlin.collections.List <Kotlin.Any?> To kotlin.colletions.List <Waypoint>


108

मैं एक फ़ंक्शन लिखना चाहता हूं जो प्रत्येक आइटम को उस में लौटाता Listहै जो पहले या अंतिम आइटम (एक बिंदु के माध्यम से) नहीं है। फ़ंक्शन List<*>को इनपुट के रूप में एक सामान्य मिलता है । एक परिणाम केवल तभी लौटाया जाना चाहिए जब सूची के तत्व प्रकार के हों Waypoint:

fun getViaPoints(list: List<*>): List<Waypoint>? {

    list.forEach { if(it !is Waypoint ) return null }

    val waypointList = list as? List<Waypoint> ?: return null

    return waypointList.filter{ waypointList.indexOf(it) != 0 && waypointList.indexOf(it) != waypointList.lastIndex}
}

जब कास्टिंग List<*>के लिए List<Waypoint>, मैं चेतावनी मिलती है:

अनियंत्रित कास्ट: kotlin.collections.List से kotlin.colletions.List

मैं अन्यथा इसे लागू करने का कोई तरीका नहीं निकाल सकता। इस चेतावनी के बिना इस फ़ंक्शन को लागू करने का सही तरीका क्या है?

जवाबों:


190

कोटलिन में, सामान्य स्थिति में रनटाइम पर जेनेरिक मापदंडों की जांच करने का कोई तरीका नहीं है (जैसे कि केवल एक आइटम की जांच करना List<T>, जो केवल एक विशेष मामला है), इसलिए एक सामान्य प्रकार को दूसरे जेनेरिक मापदंडों के साथ कास्टिंग करना एक चेतावनी को बढ़ाएगा जब तक कि विचरण सीमा के भीतर निहित है ।

हालांकि, अलग-अलग समाधान हैं:

  • आपने प्रकार की जाँच की है और आप सुनिश्चित हैं कि कलाकार सुरक्षित है। कि देखते हुए, आप कर सकते हैं चेतावनी को दबाने के साथ @Suppress("UNCHECKED_CAST")

    @Suppress("UNCHECKED_CAST")
    val waypointList = list as? List<Waypoint> ?: return null
    
  • .filterIsInstance<T>()फ़ंक्शन का उपयोग करें , जो आइटम प्रकारों की जांच करता है और पारित प्रकार के आइटमों के साथ एक सूची देता है:

    val waypointList: List<Waypoint> = list.filterIsInstance<Waypoint>()
    
    if (waypointList.size != list.size)
        return null
    

    या एक बयान में समान:

    val waypointList = list.filterIsInstance<Waypoint>()
        .apply { if (size != list.size) return null }
    

    यह वांछित प्रकार की एक नई सूची बनाएगा (इस प्रकार अनियंत्रित कलाकारों से बचना), थोड़ा ओवरहेड शुरू करना, लेकिन एक ही समय में यह आपको इसके माध्यम से चलने listऔर प्रकारों की जांच करने से बचाता है ( list.foreach { ... }इसलिए लाइन में), तो यह नहीं होगा ध्यान देने योग्य।

  • एक उपयोगिता फ़ंक्शन लिखें जो प्रकार की जांच करता है और यदि समान है, तो उसी सूची को वापस लौटाता है, इस प्रकार कलाकारों को संलग्न करता है (अभी भी संकलक के दृष्टिकोण से अनियंत्रित):

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T : Any> List<*>.checkItemsAre() =
            if (all { it is T })
                this as List<T>
            else null
    

    उपयोग के साथ:

    val waypointList = list.checkItemsAre<Waypoint>() ?: return null

6
बहुत बढ़िया जवाब! मैं list.filterIsInstance <Waypoint> () समाधान चुनता हूं क्योंकि मुझे लगता है कि यह सबसे साफ समाधान है।
लुकास लीचनर

4
ध्यान दें कि यदि आप उपयोग करते हैं filterIsInstanceऔर मूल सूची में एक अलग प्रकार के तत्व हैं तो आपका कोड चुपचाप उन्हें फ़िल्टर कर देगा। कभी-कभी यही आप चाहते हैं, लेकिन कभी-कभी आपके पास एक IllegalStateExceptionया समान फेंक दिया जा सकता है। यदि बाद में मामला है तो आप अपनी जाँच करने के लिए अपना तरीका बना सकते हैं और फिर डाल सकते हैं:inline fun <reified R> Iterable<*>.mapAsInstance() = map { it.apply { check(this is R) } as R }
mfulton26

3
ध्यान दें कि .applyलैम्ब्डा का रिटर्न मान वापस नहीं होता है, यह प्राप्त वस्तु को वापस करता है। आप संभवतया उपयोग करना चाहते हैं .takeIfयदि आप अशक्त वापस करने का विकल्प चाहते हैं।
bj0

10

@ हॉटकी के उत्तर को बेहतर बनाने के लिए यहां मेरा समाधान है:

val waypointList = list.filterIsInstance<Waypoint>().takeIf { it.size == list.size }

यह आपको देता है List<Waypoint>यदि सभी वस्तुओं को कास्ट किया जा सकता है, अन्यथा शून्य।


3

सामान्य कक्षाओं के मामले में जातियों की जाँच नहीं की जा सकती है क्योंकि प्रकार की जानकारी रनटाइम में मिटा दी जाती है। लेकिन आप जांचते हैं कि सूची में सभी ऑब्जेक्ट्स हैं Waypointइसलिए आप केवल चेतावनी को दबा सकते हैं @Suppress("UNCHECKED_CAST")

ऐसी चेतावनियों से बचने के लिए आपको Listपरिवर्तनीय वस्तुओं को पास करना होगा Waypoint। जब आप उपयोग कर रहे हैं, *लेकिन इस सूची को एक टाइप की गई सूची के रूप में एक्सेस करने की कोशिश कर रहे हैं, तो आपको हमेशा एक कलाकार की आवश्यकता होगी और यह कलाकार अनियंत्रित होगा।


1

जब सूची वस्तुओं में सीरियल की जाँच करने के लिए उपयोग किया जाता है तो मैंने @hotkey उत्तर में थोड़ा बदलाव किया:

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T : Any> Serializable.checkSerializableIsListOf() =
        if (this is List<*> && this.all { it is T })
          this as List<T>
        else null

इस तरह एक समाधान की तलाश में था, लेकिन यह त्रुटियां हैं:Cannot access 'Serializable': it is internal in 'kotlin.io'
daviscodesbugs

0

के बजाय

myGenericList.filter { it is AbstractRobotTurn } as List<AbstractRobotTurn>

मुझे करना पसंद है

myGenericList.filter { it is AbstractRobotTurn }.map { it as AbstractRobotTurn }

यह सुनिश्चित नहीं है कि यह कैसा प्रदर्शन है, लेकिन कम से कम कोई चेतावनी नहीं।

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