Ваш список имеет наименьший общий тип для Foo
и Bar
- Any
, вы должны проверить тип в своей лямбде перед вызовом run
метода:
class Foo
class Bar
fun Foo.run() = "Foo.run"
fun Bar.run() = "Bar.run"
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar())
val y = x.map({ a ->
when (a) {
is Foo -> a.run()
is Bar -> a.run()
else -> {
/* ignore */
}
}
})
println("Hello, world!")
}
или
class Foo
class Bar
fun Foo.run() = "Foo.run"
fun Bar.run() = "Bar.run"
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar())
val y = x.map({ a ->(a as? Foo)?.run() ?: (a as? Bar)?.run() })
println("Hello, world!")
}
Поскольку выводимый тип элементов в x
равен Any
, он может содержать элементы, отличные от Foo
и Bar
, поэтому ваш код не найдет метод для такого элемента, и это проверяется при компиляции время.
И даже если вы добавите функцию расширения с проверкой типа reified, она будет преобразована в наименьший общий родительский элемент:
class Foo
class Bar
fun Foo.run() = "Foo.run"
fun Bar.run() = "Bar.run"
fun Any.run() = "Any.run" // this is type erasured version of 'inline fun <reified T> T.run() = T::class.simpleName+".run"'
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar())
val y = x.map(Any::run)
println(y)
}
напечатает [Any.run, Any.run]
Но используя ссылку на this
, вы можете предоставить данные для вашей функции, например:
class Foo
class Bar
inline fun Any.run() = this::class.simpleName + ".run"
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar())
val y = x.map(Any::run)
println(y)
}
напечатает [Foo.run, Bar.run]
Вы также можете переместить отправляющий код тип дочернего класса в функцию расширения, например:
class Foo
class Bar
fun Foo.run() = "Foo!!!.run"
fun Bar.run() = "Bar!!!.run"
fun Any.run() = when(this){
is Foo -> run()
is Bar -> run()
else -> { "Unknown.run" }
}
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar(), Any())
val y = x.map({ a -> a.run()
})
println(y)
}
напечатает [Foo!!!.run, Bar!!!.run, Unknown.run]