【问题标题】:How to convert function output to Unit with Kotlin如何使用 Kotlin 将函数输出转换为 Unit
【发布时间】:2020-02-14 08:44:04
【问题描述】:

我在 Kotlin 中应该返回 Unit 的函数遇到问题,但由于使用了另一个返回布尔值的函数,存在类型不匹配。

这是一个人为的例子:

fun printAndReturnTrue(bar: Int): Boolean {
    println(bar)
    return true
}

fun foo(bar: Int): Unit = when(bar) {
    0 -> println("0")
    else -> printAndReturnTrue(bar)
}

在这里,我实际上并不关心printAndReturnTrue 返回布尔值的事实。我只想 foo 执行副作用操作。但是编译器会警告类型不匹配:我的else 应该返回一个Unit 值。

有没有很好的方法将值转换为Unit

我看到的最简单的解决方案是:

fun foo(bar: Int): Unit = when(bar) {
    0 -> println("0")
    else -> { 
        printAndReturnTrue(bar)
        Unit
    }
}

或:

fun foo(bar: Int): Unit = when(bar) {
    0 -> println("0")
    else -> eraseReturnValue(printAndReturnTrue(bar))
}

fun eraseReturnValue(value: Any) = Unit

或者我使用全函数形式:

fun foo(bar: Int): Unit { 
    when(bar) {
        0 -> println("0")
        else -> printAndReturnTrue(bar)
    }
}

我确信有一些惯用的方法可以做到这一点(或者是最后一个例子?),但现在我没有找到它们。

【问题讨论】:

    标签: function return kotlin


    【解决方案1】:

    不幸的是,没有惯用的方法可以做到这一点。一个类似的问题,将一个 (T) -> Boolean 类型的 lambda 传递给一个接受 (T) -> Unit lambdas 的函数之前已经出现过,并且那里需要的自动转换应该会在将来的某个时候出现在该语言中。

    目前,您可以在 when 表达式末尾使用扩展函数将其强制转换为 Unit 值:

    fun Any?.toUnit() = Unit
    
    fun foo(bar: Int): Unit = when(bar) {
        0 -> println("0")
        else -> printAndReturnTrue(bar)
    }.toUnit()
    

    或者,一个扩展属性,如果你碰巧更喜欢它:

    val Any?.unit get() = Unit
    
    fun foo(bar: Int): Unit = when(bar) {
        0 -> println("0")
        else -> printAndReturnTrue(bar)
    }.unit
    

    当然,如果您使用其中任何一个,您可以省略函数的显式 Unit 返回类型。

    【讨论】:

    • 其他非常好的 lambda 类型示例。事后我认为使用“=”版本的函数不是好方法,但似乎还有其他有效的情况可能会出现问题。
    【解决方案2】:

    我认为最后一个是最惯用的。虽然你不需要显式的: Unit,但如果没有指定返回类型,它是块形式的默认值,如果你尝试返回其他东西,你会得到一个错误。

    但请注意一个微妙的细节:当when 用作表达式时,else 是必需的,除非编译器能够证明所有情况都已处理;在块形式中,它“用作语句”并且忽略未处理的情况。

    【讨论】:

      【解决方案3】:

      作为另一种选择,您可以创建一个高阶函数来吞下函数的输出并返回一个值:

      fun consume (fn: () -> Any): Unit {
        fn()
      }
      

      给予:

      fun foo(bar: Int): Unit = when(bar) {
          0 -> println("0")
          else -> consume { printAndReturnTrue(bar) }
      }
      

      【讨论】:

      • 为了更好的可读性,该方法可以命名为toUnit。它甚至可以接受值,而不是 lambda:fun toUnit(value: Any?): Unit {} 和用法:else -> toUnit(printAndReturnTrue(bar))
      【解决方案4】:

      如果我在一行中写,我只使用分号。

      someExpression; Unit
      

      【讨论】:

        【解决方案5】:

        我认为您应该将函数的返回类型更改为可选,这样更清楚,如下所示:

        fun printAndReturnTrue(bar: Int): Boolean {
            println(bar)
            return true
        }
        
        fun foo(bar: Int): Unit? = when(bar) {
            0 -> println("0")
            else -> printAndReturnTrue(bar) as? Unit
        }
        

        【讨论】:

          【解决方案6】:

          你也可以这样做

          fun foo(bar: Int): Unit = when(bar) {
              0 -> println("0")
              else -> printAndReturnTrue(bar).let{ Unit }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-12-28
            • 2019-02-08
            • 1970-01-01
            • 1970-01-01
            • 2021-07-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多