Лямбда игнорируются до тех пор, пока не будет добавлено "run"

У меня есть цепочка RX, которая вызывает API через Retrofit. Я подписываюсь на мой сервис API со стандартным rx subscribe({...}) метод и передать лямбду к нему. К сожалению, когда мой вызов, наконец, завершен, весь код, который я добавил для выполнения внутри лямбды, полностью игнорируется. AndroidStudio предложила исправление, которое в основном добавляет встроенную функцию run к моей лямде и... это волшебно работает. Я понятия не имею, что происходит. Почему это не работает без run? Что значит run делать?

Код следует:

valuesServiceApi.getValues()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ data ->
                run { //<- What's this?
                    val cs = data.creditReportInfo.score
                    view.setCreditScore(cs)
                    Logger.getLogger("success:").info("credit score $cs")
                }

            })

2 ответа

Решение

{ expressions } это короткая форма { -> expressions }, который является литералом функции с нулевыми параметрами.

Следовательно,

{ data ->
    {
        val cs = data.creditReportInfo.score
        view.setCreditScore(cs)
        Logger.getLogger("success:").info("credit score $cs")
     }
}

такой же как

{ data ->
    { ->
        val cs = data.creditReportInfo.score
        view.setCreditScore(cs)
        Logger.getLogger("success:").info("credit score $cs")
    }
}

который создает лямбда-выражение, и ничего не делать с ним.

Что вы хотите сделать, это

{ data ->
    { ->
        val cs = data.creditReportInfo.score
        view.setCreditScore(cs)
        Logger.getLogger("success:").info("credit score $cs")
    }()
}

но это так же, как

{ data ->
    val cs = data.creditReportInfo.score
    view.setCreditScore(cs)
    Logger.getLogger("success:").info("credit score $cs")
}

плюс дополнительные затраты на создание функций.

run { ... } такой же как { ... }() минус дополнительная временная функция создания накладных расходов. Таким образом, выше, так же, как

{ data ->
    run { ->
        val cs = data.creditReportInfo.score
        view.setCreditScore(cs)
        Logger.getLogger("success:").info("credit score $cs")
    }
}

Посмотрите на определение run функция. Это простая встроенная функция, которая практически ничего не делает. Я использую это, чтобы отделить мою логику в Kotlin.

val runResult = run { // 
  // Do something in here that doesn't impact the rest of my algorithm / code
  val a = 1
  val b = 2
  a + b // return a + b
}

// Can't access a or b here. run successfully keeps the rest of my algorithm separate / clean

Вы также можете использовать run Метод для создания свойства inline:

class Example {
  /**
   * Will have the value "0123456789"
   */
  val exampleString: String = run { //
    val sb = StringBuilder()
    for (i in 0..9) {
      sb.append(i)
    }
    sb.toString()
  }
}

Теперь, как говорится, run определенно не влияет на ваш код RxJava вообще. Я рекомендую вам очистить ваш проект и запустить его снова. Кроме того, kotlin предлагает более приятный синтаксис для функций, которые имеют лямбду для последнего параметра. Если бы я писал это, я написал бы следующий код с эквивалентным синтаксисом того, что вы написали:

valuesServiceApi.getValues()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { data ->
            val cs = data.creditReportInfo.score
            view.setCreditScore(cs)
            Logger.getLogger("success:").info("credit score $cs")
        }
Другие вопросы по тегам