android - Kotlin: Get list item of certain type passed in function - Stack Overflow

Trying to get list item of certain type passed in function. This code works as expected, but it looks n

Trying to get list item of certain type passed in function. This code works as expected, but it looks not so good. Can I check classes types into firstOrNull lambda directly, instead of comparing names?

fun <T: TripManagerModule> getModule(moduleType: KClass<T>): T? {
    return modules
        .firstOrNull { it::class.simpleName == moduleType.simpleName }
        ?.let { it as? T } //Warning here: "Unchecked cast: TripManagerModule to T"
}

val module = getModule(TripArrivalDelayManager::class)

Trying to get list item of certain type passed in function. This code works as expected, but it looks not so good. Can I check classes types into firstOrNull lambda directly, instead of comparing names?

fun <T: TripManagerModule> getModule(moduleType: KClass<T>): T? {
    return modules
        .firstOrNull { it::class.simpleName == moduleType.simpleName }
        ?.let { it as? T } //Warning here: "Unchecked cast: TripManagerModule to T"
}

val module = getModule(TripArrivalDelayManager::class)
Share Improve this question asked Feb 12 at 21:20 Konstantin KonopkoKonstantin Konopko 5,4344 gold badges39 silver badges66 bronze badges 0
Add a comment  | 

2 Answers 2

Reset to default 2

You can utilize filterIsInstance() that preserves the type of the list:

fun <T : TripManagerModule> getModule(moduleType: KClass<T>): T? =
    modules
        .filterIsInstance(moduleType.java)
        .firstOrNull()

You don't need to cast anymore, it will already be of the correct type.

And if you want to get rid of the parameter you can make the function inline:

inline fun <reified T : TripManagerModule> getModule(): T? =
    modules
        .filterIsInstance<T>()
        .firstOrNull()

You can then call it like this

val module = getModule<TripArrivalDelayManager>()

or let the compiler infer the type, for example like this:

val module: TripArrivalDelayManager? = getModule()

You can compare the class objects directly. From KClass::equals (specifically the JVM docs):

Returns true if this KClass instance represents the same Kotlin class as the class represented by other. On JVM this means that all of the following conditions are satisfied:

  1. other has the same (fully qualified) Kotlin class name as this instance.

  2. other's backing Class object is loaded with the same class loader as the Class object of this instance.

  3. If the classes represent Array, then Class objects of their element types are equal.

For example, on JVM, KClass instances for a primitive type (int) and the corresponding wrapper type (java.lang.Integer) are considered equal, because they have the same fully qualified name "kotlin.Int".

And since you have the KClass, you can use it to cast the element to avoid the unchecked cast warning.

fun <T : TripManagerModule> getModule(moduleType: KClass<T>): T? {
  return modules.firstOrNull { it::class == moduleType }?.let(moduleType::cast)
}

That will return the first element whose class is exactly moduleType (or null if no such element exists). However, if you want the first instance of moduleType, then you can use isInstance.

fun <T : TripManagerModule> getModule(moduleType: KClass<T>): T? {
  return modules.firstOrNull(moduleType::isInstance)?.let(moduleType::cast)
}

And if you want, you can add the following convenience inline function:

inline fun <reified T : TripManagerModule> getModule() = getModule(T::class)

Which would let you call the function like:

val module = getModule<SomeModuleType>()

Instead of only like:

val module = getModule(SomeModuleType::class)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745201539a4616353.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信