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
2 Answers
Reset to default 2You 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:
other has the same (fully qualified) Kotlin class name as this instance.
other's backing Class object is loaded with the same class loader as the Class object of this instance.
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条)