কোটলিন: তালিকাভুক্ত ক্যাস্টগুলির সাথে কীভাবে কাজ করবেন: চেক না করা কাস্ট: কোটলিন.কলেকশনস L তালিকা করুন <কোটলিন.আনি?> থেকে কোটলিন.কলেশনস.লাইস্ট <ওয়েইপয়েন্ট>


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>, আমি সতর্কতাটি পেয়েছি:

চেক না করা কাস্ট: কোটলিন.কলেকশনস kot লিস্টে কোটলিন.কলেশন.লাইস্ট

অন্যথায় এটি বাস্তবায়নের কোনও উপায় আমি বের করতে পারি না। এই সতর্কতা ছাড়াই এই ফাংশনটি বাস্তবায়নের সঠিক উপায় কী?

উত্তর:


190

কোটলিনে, সাধারণ ক্ষেত্রে রানটাইমের সময় জেনেরিক প্যারামিটারগুলি পরীক্ষা করার কোনও উপায় নেই (যেমন কেবল একটি এর আইটেমগুলি পরীক্ষা করা List<T>, যা কেবলমাত্র একটি বিশেষ কেস), তাই জেনেরিক টাইপটিকে অন্য জেনেরিক পরামিতি সহ অন্যটিতে জালানো সতর্কতা বাড়াবে যদি না ভেরিয়েন্স সীমা মধ্যে মিথ্যা নিক্ষেপ ।

বিভিন্ন সমাধান আছে, তবে:

  • আপনি প্রকারটি পরীক্ষা করেছেন এবং আপনি নিশ্চিত যে castালাই নিরাপদ। এটি দেওয়া, আপনি সতর্কতা দিয়ে দমন করতে পারেন @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 }

    এটি পছন্দসই প্রকারের একটি নতুন তালিকা তৈরি করবে (এভাবে অভ্যন্তরে চেক না করা avoালাই এড়ানো), একটি সামান্য ওভারহেড প্রবর্তন করবে, তবে একই সময়ে এটি আপনাকে পুনরাবৃত্তি করতে 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 <ওয়েওপয়েন্ট> () সমাধানটি বেছে নিই কারণ আমি মনে করি এটি সবচেয়ে পরিষ্কার সমাধান।
লুকাশ ল্যাটারের

4
মনে রাখবেন যে আপনি যদি ব্যবহার করেন filterIsInstanceএবং মূল তালিকায় কোনও ভিন্ন ধরণের উপাদান থাকে তবে আপনার কোডগুলি নিঃশব্দে সেগুলি ফিল্টার করে দেবে। কখনও কখনও আপনি যা চান এটি এটি আবার কখনও কখনও আপনি বরং একটি IllegalStateExceptionঅনুরূপ নিক্ষেপ হতে পারে । যদি পরে এটি হয় তবে আপনি নিজের পরীক্ষা করার জন্য নিজস্ব পদ্ধতি তৈরি করতে পারেন এবং তারপরে কাস্ট করতে পারেন:inline fun <reified R> Iterable<*>.mapAsInstance() = map { it.apply { check(this is R) } as R }
এমফুল্টন 26

3
নোট করুন যে .applyল্যাম্বদার রিটার্ন মানটি ফেরত দেয় না, এটি গ্রহণের বস্তুটি প্রদান করে। আপনি .takeIfযদি কোনও নাল ফেরানোর বিকল্প চান তবে আপনি সম্ভবত ব্যবহার করতে চান।
বিজে 0

10

@ হটকি এর উত্তর উন্নত করতে এখানে আমার সমাধানটি দেওয়া হয়েছে:

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

এটি আপনাকে দেয় List<Waypoint>যদি সমস্ত আইটেম কাস্ট করা যায়, অন্যথায় নালায়।


3

জেনেরিক ক্লাসের ক্ষেত্রে কাস্টগুলি পরীক্ষা করা যায় না কারণ রানটাইমের ধরণের তথ্য মুছে ফেলা হয়। তবে আপনি যাচাই করেছেন যে তালিকার সমস্ত বস্তু Waypointগুলি যাতে আপনি কেবল সতর্কতাটি দমন করতে পারেন @Suppress("UNCHECKED_CAST")

এই ধরনের সতর্কতা এড়ানোর জন্য আপনাকে Listরূপান্তরযোগ্য কিছু বস্তু পাস করতে হবে Waypoint। আপনি যখন ব্যবহার করছেন *তবে টাইপ করা তালিকা হিসাবে এই তালিকাটি অ্যাক্সেস করার চেষ্টা করছেন আপনার সর্বদা একটি কাস্টের প্রয়োজন হবে এবং এই কাস্টটি চেক করা হবে না।


1

অবজেক্টের তালিকাতে সিরিয়ালযোগ্যযোগ্য পরীক্ষা করার জন্য আমি @ হটকি জবাবটিতে কিছুটা পরিবর্তন করেছি:

    @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'
করছিল

0

পরিবর্তে

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

আমি করতে পছন্দ করি

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

এটি কতটা পারফরম্যান্ট তা নিশ্চিত নয় তবে কমপক্ষে কোনও সতর্কতা নেই।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.