Проверить, является ли выражение пустым в стиле Kotlin, Lua? - PullRequest
1 голос
/ 27 октября 2019

В Lua (который редко используется вне разработки в Corona SDK), вы можете оценить ЛЮБОЕ выражение в выражении if следующим образом:

  1. Если выражениеnull, вернет 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) это ленивее , и мне нравится быть ленивым:)

Ответы [ 2 ]

2 голосов
/ 27 октября 2019

Ссылаясь на спецификацию языка Kotlin :

Тип выражения условия должен быть подтипом kotlin.Boolean, в противном случае это ошибка.

Так что нет, в Kotlin нет прямого эквивалента.

Однако вы можете потенциально эмулировать поведение, используя пользовательскую функцию расширения в Any?:

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

Хотя не уверен, что это будет считаться "более ленивым".

1 голос
/ 27 октября 2019

Чтобы сделать его более удобным, вы можете создать функцию более высокого порядка 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 class:

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

Я уже задавал вопрос об этом исключении.

...