2016-04-12 24 views
19

için ilk veya son öğe olmayan bir List her öğeyi döndüren bir işlev yazmak istiyorum (bir geçiş noktası). İşlev, giriş olarak genel bir List<*> alır.Kotlin: List ile nasıl çalışılır atmalarını: İşaretlenmemiş Cast: kotlin.collections.List <Kotlin.Any?> kotlin.colletions.List <Waypoint>

denetlenmeyen Oyuncular:: kotlin.collections

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<*> için List<Waypoint> döküm, ben uyarı olsun: Listenin elemanları tip Waypoint arasında ise bir sonuç yalnızca döndürülmelidir. Liste

Ben başka türlü uygulamanın bir yolunu anlamaya olamaz kotlin.colletions.List için. Bu uyarıyı bu uyarı olmadan uygulamak için doğru yol nedir?

cevap

52

Kotlin'de, genel durumda çalışma zamanında genel parametreleri kontrol etmenin bir yolu yoktur (yalnızca özel bir durum olan List<T> öğelerini kontrol etmek gibi), böylece farklı genel parametrelere sahip genel bir türe dökülecek cast, variance bounds içinde bulunmadığı sürece bir uyarı oluşturmak.

ancak farklı çözümler vardır:

  • Sen türünü de kontrol etmenize dökme güvenli olduğundan oldukça eminiz. Bunu göz önüne alarak, @Suppress("UNCHECKED_CAST") ile suppress the warning yapabilirsiniz.

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

    veya bir açıklamada aynı:

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

    öğe türlerini denetler ve geçirilen türündeki öğeler içeren bir liste döndürür

    @Suppress("UNCHECKED_CAST") 
    val waypointList = list as? List<Waypoint> ?: return null 
    
  • Kullanım .filterIsInstance<T>() fonksiyonu, Bu, istenen tipte yeni bir liste oluşturacak (böylece içeride kontrol edilmeyen satırlardan kaçınılacaktır), biraz daha fazla yük getirecek, ancak aynı zamanda sizi tekrar eden list numarasına gidin ve türleri kontrol edin (list.foreach { ... } satırında), bu nedenle fark edilmeyecektir.Ile

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

    :

  • türü böylece, içinde (bakış derleyici'nın noktasından yine işaretlenmemiş) döküm kapsül, doğru ise aynı liste tip kontrol eder ve döner bir yardımcı işlev Yazın kullanımı:

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

Mükemmel Yanıt! List.filterIsInstance () çözümünü seçtim çünkü en temiz çözüm olduğunu düşünüyorum. – lukle

+3

kullanmak eğer Not: [ 'filterIsInstance'] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter-is-instance.html) ve orijinal liste farklı tipte elemanlar içerir kodunuz onları sessizce filtreleyecek. Bazen istediğin budur ama bazen bir "IllegalStateException" veya benzer bir atılmış olabilir. Daha sonra durumda ardından denetlemek için kendi yöntemini oluşturmak ve sonra yayınlayabileceğim: ' – mfulton26

+0

Not {R (bu R)} it.apply {onay}' satır içi eğlence iterable <*> .mapAsInstance() = haritası bu '.apply', lambda'nın dönüş değerini döndürmez, alma nesnesini döndürür. Büyük olasılıkla bir null döndürme seçeneğini kullanmak istiyorsanız '.takeIf' kullanmak isteyebilirsiniz. – bj0

2

Genel sınıflar söz konusu olduğunda, dökümler çalışma zamanı içinde tip bilgisi silindiğinden kontrol edilemez. Ancak listedeki tüm nesnelerin Waypoint s olduğunu kontrol edersiniz, böylece uyarıyı sadece @Suppress("UNCHECKED_CAST") ile kaldırabilirsiniz.

Bu tür uyarılardan kaçınmak için Waypoint'a dönüştürülebilen bir List nesnesini geçirmeniz gerekir. *'u kullanırken ancak bu listeye yazılan bir liste olarak erişmeye çalıştığınızda, her zaman bir döküm işlemine ihtiyacınız olur ve bu yayın devre dışı bırakılır.

İlgili konular