[list] Kotlin : List 캐스트 작업 방법 : Unchecked Cast : kotlin.collections.List <Kotlin.Any?> to kotlin.colletions.List <Waypoint>

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로

나는 그것을 구현하는 방법을 알아낼 수 없습니다. 이 경고없이이 기능을 구현하는 올바른 방법은 무엇입니까?



답변

Kotlin에서는 일반적으로 런타임에 일반 매개 변수를 확인할 수있는 방법이 없습니다 (예 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

답변

@hotkey의 답변을 개선하려면 여기에 내 솔루션이 있습니다.

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

이렇게 List<Waypoint>하면 모든 항목을 캐스트 할 수 있는지 여부를, 그렇지 않으면 null을 제공합니다.


답변

제네릭 클래스의 경우 런타임에서 유형 정보가 지워지기 때문에 캐스트를 확인할 수 없습니다. 그러나 목록의 모든 개체가 Waypoints 인지 확인 하여을 사용하여 경고를 억제 할 수 있습니다 @Suppress("UNCHECKED_CAST").

이러한 경고를 피하려면 List로 변환 할 수있는 객체 를 전달해야합니다 Waypoint. 사용 *중이지만 입력 된 목록으로이 목록에 액세스하려는 경우 항상 캐스트가 필요하며이 캐스트는 선택 취소됩니다.


답변

Serializable to List 객체를 확인하는 데 사용할 때 @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


답변

대신에

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

나는하는 것을 좋아한다

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

이것이 얼마나 성능이 좋은지는 확실하지 않지만 적어도 경고는 없습니다.


답변