Разница между тем и запуском в Котлине

Do with и run имеют одинаковую функциональность только с другим синтаксисом или существуют какие-либо существенные различия между with и run?

Каков правильный способ?

adapter.run {
    notifyDataSetChanged()
    if (activityDetails.isEmpty())
        emptyText.visibility = View.VISIBLE
    else 
       emptyText.visibility = View.GONE
}


with(adapter){
   notifyDataSetChanged()
   if (activityDetails.isEmpty())
       emptyText.visibility = View.VISIBLE
   else 
       emptyText.visibility = View.GONE
}

Ответы

Ответ 1

Они имеют только синтаксическую разницу, run является функцией расширения, а with - нет. Вот определения (в kotlin-sdlib:1.0.3):

public inline fun <T, R> T.run(block: T.() -> R): R = block() // equivalent to this.block()

public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

Так как run является функцией расширения, у нее есть еще один неявный аргумент типа T, поэтому типы аргументов одинаковы. Тела функций также фактически одинаковы.

Их производительность также должна быть эквивалентной, так как обе функции inline: полученный байт-код должен содержать только встроенный block body.


Различия в использовании функций обусловлены тем, что run является расширением.

Во-первых, run подходит для цепочки вызовов:

foo.run { bar }.run { baz }

Во-вторых, и что более важно, если объявленный тип переменной имеет функцию run с той же сигнатурой, она будет вызываться вместо расширения. И run можно затенять другим расширением. Это как расширяются расширения. Пример:

class MyClass {
     fun <R> run(blockIgnored: MyClass.() -> R): Nothing = throw RuntimeException()
}

"abcdefg".run { println("x") } // prints "x"
MyClass().run { println("x") } // throws RuntimeException
(MyClass() as Any).run { println("x") } // prints "x"

Ответ 2

В нормальном случае они довольно похожи, но для переменной с нулевым значением лучше использовать T.run()

например. если webview.settings является нулевым, ниже будет отображаться отдельный

with(webview.settings) {
    this?.javaScriptEnabled = true
    this?.databaseEnabled = true
}

// similarly
webview.settings?.run {
    javaScriptEnabled = true
    databaseEnabled = true
}