【问题标题】:How to check if an argument is a lambda如何检查参数是否为 lambda
【发布时间】:2018-08-06 13:23:53
【问题描述】:

我正在处理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){ 行无法编译并显示以下消息:Cannot check for instance of erased type: () -> Unit

有没有办法在运行时检查对象是否为() -> Unit

我见过another answer that recommends using wildcards。我认为这无关紧要:我的代码不使用泛型。

【问题讨论】:

标签: lambda kotlin


【解决方案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&lt;Unit&gt; 还是 Function0&lt;Int&gt;,因为类型不可用在运行时让您做出决定。这意味着有人可以给你一个返回某些东西的 lambda,而你会忽略结果。

【讨论】:

  • 完美运行!泰!
【解决方案2】:

您的MyCustomType 本身不是Function0 有什么原因吗? 如果是这样,您可以只使用vararg commands : () -&gt; 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") })

此外,如果您要求所有命令都具有特定的返回值,您仍然可以这样做,例如如果您的所有命令都必须返回String,则只需使用vararg commands: () -&gt; String

在这方面使用Any 可能会在未来导致头痛。如果您缩小您的类型,您至少可以确定您将始终拥有以相同方式运行的命令。此外,您可以通过这种方式获得最好的代码完成支持。 Any 可以传递任何东西,但 run 不能传递任何东西。

如果你只想检查一个参数是否是一个lambda,你也可以使用如下:

someObj is Function<*>

但是你不能调用 invoke 而不将其转换为特定的函数类型,即:Function0Function1 等。 关于Function0 等。托德已经回答了这个问题。但正如他在警告中提到的那样:这样做有不利之处。我只能建议尽可能省略Any

【讨论】:

  • 有道理。一定会这样做的。
猜你喜欢
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2016-03-28
  • 2017-04-11
相关资源
最近更新 更多