【问题标题】:Check if expression is null in Kotlin, Lua-style?检查 Kotlin 中的表达式是否为空,Lua 风格?
【发布时间】:2019-10-28 06:54:05
【问题描述】:

Lua(在 Corona SDK 的开发之外很少使用)中,您可以在 if 语句中评估任何表达式,如下所示:

  1. 如果表达式为空,将返回false
  2. 如果表达式是布尔值false,将返回false
  3. 其他所有内容都会返回true

例子

if (1) // true
if ("Hello World") // true
if (instanceOfSomeRandomClass) // true
if ( [2, null, "foo"] ) // true
if (thisFunctionCallWithReturnNull()) // false
if (0 == 1) // false

if 也恰好是 Kotlin 中的一个表达式,因此结合这些功能,我可以看到创造性地使用它。

在 Kotlin 中是否有等价物?

我知道你总是可以手动检查if (expression != null),这并没有什么问题,但是if (expression) 更懒惰,我喜欢懒惰:)

【问题讨论】:

    标签: if-statement kotlin lua


    【解决方案1】:

    引用Kotlin language specification

    条件表达式的类型必须是kotlin.Boolean的子类型,否则报错。

    所以不,Kotlin 中没有直接的等价物。

    但是,您可以在 Any? 上使用自定义 extension function 来模拟该行为:

    fun Any?.toBoolean() = this != null && this != false
    

    查看实际情况(注意input.toBoolean()):

    fun main() {
        evaluate(1)
        evaluate("Hello World")
        evaluate(String())
        evaluate(listOf(2, null, "foo"))
        evaluate(null)
        evaluate(0 == 1)
    }
    
    fun evaluate(input: Any?) {
        println("$input is ${input.toBoolean()}")
    }
    

    输出:

    1 is true
    Hello World is true
     is true
    [2, null, foo] is true
    null is false
    false is false
    

    但不确定这是否符合“懒惰”的条件。

    【讨论】:

      【解决方案2】:

      为了更方便,可以创建一个高阶的luaIf函数:

      sealed class LuaIf<T> {
          class True<T>(val value: T) : LuaIf<T>()
          object False : LuaIf<Nothing>()
      }
      
      inline fun <T> luaIf(condition: Any?, block: () -> T): LuaIf<T> =
          if (condition == null || condition == false) False as LuaIf<T>
          else True(block())
      
      inline infix fun <T : R, R> LuaIf<T>.els(ifFalse: () -> R): R = when (this) {
          is True -> value
          False -> ifFalse()
      }
      

      并像这样使用它:

      luaIf(null) { 1 } els { 0.5 } // 0.5
      luaIf(Any()) { 1 } els { 0.5 } // 1
      

      不幸的是,每次条件为true(或不是null)时,都会创建LuaIf.True 实例。你可以通过内联LuaIf类来优化它:

      inline class LuaIf<T> @Deprecated(
          message = "Not type-safe, use factory method",
          replaceWith = ReplaceWith("luaIf(true) { _value }", "package.file.luaIf")
      ) constructor(val _value: Any?)
      
      object LuaIfFalse
      
      inline fun <T> luaIf(condition: Any?, ifTrue: () -> T): LuaIf<T> =
          if (condition == null || condition == false) LuaIf(LuaIfFalse)
          else LuaIf(ifTrue())
      
      inline infix fun <T : R, R> LuaIf<T>.els(ifFalse: () -> R): R =
          if (_value == LuaIfFalse) ifFalse()
          else _value as T
      

      现在,如果您查看println(luaIf(nullableAny) { 1 } els { 0.5 }) 的字节码,您将看到没有创建其他对象。这是我反编译的字节码:

      Object $this$els$iv = LuaIf.constructor-impl(
              nullableAny != null && !Intrinsics.areEqual(nullableAny, false) ? 1 : LuaIfFalse.INSTANCE
      );
      System.out.println(
              Intrinsics.areEqual($this$els$iv, LuaIfFalse.INSTANCE) ? 0.5 : $this$els$iv
      );
      
      public final class LuaIf {
         public static Object constructor-impl(@Nullable Object _value) {
            return _value;
         }
      }
      

      但是由于内联类是实验性的,如果你以一种奇怪的方式使用它们,它们可能会导致一些错误。比如下面的代码抛出ClassCastException: Integer cannot be cast to LuaIf

      falseLua { luaIf(0) { 0 } } els { 0 }
      
      fun <T> falseLua(other: () -> T): T = luaIf(false) { error("Impossible") } els other
      

      我已经向question 询问过这个异常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-07
        • 1970-01-01
        • 2013-11-08
        相关资源
        最近更新 更多