给出以下类和扩展函数
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.run()}) //compiler error
println("Hello, world!")
}
是否可以通用方式调用run
?
不知何故,这是尝试通过界面扩展类时模拟Swift的protocol
和extension
,或者不是可能或不可取。
答案 0 :(得分:1)
您只需要一个通用类型并扩展此类型。一个简单的标记界面将有助于此:
interface Common
class Foo: Common
class Bar: Common
fun Common.run() = "run"
fun main(args: Array<String>) {
val x = listOf(Foo(), Bar())
val y = x.map {a -> a.run() }
}
或 sealed
类(正如您在OP中所建议的那样):
sealed class Common {
class Foo: Common()
class Bar: Common()
}
fun <T: Common> T.run() = "run"
fun main(args: Array<String>) {
val x = listOf(Common.Foo(), Common.Bar())
val y = x.map {a -> a.run() }
}
答案 1 :(得分:1)
您的列表包含Foo
和Bar
- Any
的最低常见类型,您应该在调用run
方法之前检查lambda中的类型:< / p>
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 type check添加扩展功能,它也会转换为最低公共父级:
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]
答案 2 :(得分:0)
你可以这样做。
fun <T> T.run() = "run"
这个run
定义应该使代码的其余部分编译。
如果您想限制run
的被访问者,您应该像这样创建一个公共sealed class
。
class Foo : Bla()
class Bar : Bla()
sealed class Bla
fun <T : Bla>.run() = "run"
// this works, too
// fun Bla.run() = "run"
通过这种方式,只有Foo
和Bar
的实例可以使用run
。
但如果我是你,我会run
成为Bla
的成员函数。