我正在如下处理MyCustomType
的实例集合:
fun runAll(vararg commands: MyCustomType){
commands.forEach { it.myMethod() }
}
除了MyCustomType
的实例外,我还要传递和处理类型为() -> Unit
的lambda,如下所示:
fun runAll(vararg commands: Any){
for(command in commands){
if (command is MyCustomType){
command.myMethod()
} else
if(command is () -> Unit){
command.invoke()
}
}
}
第if(command is () -> Unit){
行不与以下消息一起编译:{{1}}。
是否可以在运行时检查对象是否为Cannot check for instance of erased type: () -> Unit
?
我见过another answer that recommends using wildcards。我认为这不相关:我的代码未使用泛型。
答案 0 :(得分:1)
Kotlin将把您的lambda编译为Function0
的实例。如果您知道这一点,则可以使用when
块进行比较并很好地智能投射:
fun runAll(vararg commands: Any) {
commands.forEach {
when(it) {
is Function0<*> -> it.invoke()
is MyCustomType -> it.myMethod()
}
}
}
然后调用它:
fun main(args: Array<String>) {
runAll(
MyCustomType(),
{ println("Lambda!") }
)
}
警告:此方法的缺点是使用类型擦除时,您不知道要获取Function0<Unit>
还是Function0<Int>
,因为类型在运行时无法确定。这意味着有人可以给你一个lambda,该lambda返回某些内容,而您将忽略结果。
答案 1 :(得分:0)
您的MyCustomType
本身不是Function0
的原因吗?
如果是这样,您可以只使用vararg commands : () -> Unit
,然后不管传递什么,都可以调用command()
(这与调用command.invoke()
相同)。您甚至可以使用当前代码来做到这一点:
将runAll
的签名更改为:
fun runAll(vararg commands: () -> Unit) { ...
然后使用:
runAll(MyCustomType()::myMethod, { println("self-built-function") } /*, ... */)
或同一个字母的val稍有不同:
val customObj = MyCustomType()
runAll({ customObj.myMethod() }, { println("self-built-function") })
此外,如果您要求所有命令都具有一定的返回值,则仍然可以这样做,例如如果所有命令都必须返回vararg commands: () -> String
,则只需使用String
。
在这方面使用Any
可能会在将来引起头痛。如果缩小类型的范围,则至少可以确保始终具有相同的命令行为。此外,您将以这种方式获得最佳的代码完成支持。使用Any
,您可以传递任何内容,但不能run
传递所有内容。
如果只想检查参数是否为lambda,则还可以使用以下命令:
someObj is Function<*>
但是,如果不将其强制转换为特定的函数类型,即invoke
,Function0
等,则无法调用Function1
。
关于Function0
等,托德已经回答了。但是正如他在警告中还提到的那样:这有一个缺点。我只建议您尽可能地省略Any
。