There are quite a few blog posts (like this) on usages of the standard library functions apply/with/run/also/let available that make it a bit easier to distingish when to actually use which of those pretty functions.

For a few weeks now, the official docs even provide guidelines on that topic finally: https://kotlinlang.org/docs/reference/coding-conventions.html#using-scope-functions-applywithrunalsolet

Nevertheless, I think it is pretty hard to memorize the function's individual use cases by the function names. I mean, for me they seem to be interchangeable, why isn't let called run for instance?

Any suggestions? I think the names aren't very expressive which makes it hard to see the differences at first.

推荐答案

Here's an unofficial overview of how the names seem to have come to be.

让我们

让我们的灵感来自函数式编程世界.根据Wikipedia

"让我们"表达式将函数定义与受限范围相关联

在像Haskell这样的FP语言中,可以使用让我们将值绑定到受限范围内的变量,如下所示

aaa = 让我们 y = 1+2
          z = 4+6
          in  y+z

Kotlin中的等效(尽管过于复杂)代码是

fun aaa() = (1+2).让我们 { y -> 
              (4+6).让我们 { z ->
                y + z
              } 
            }

The typical usage of 让我们 is to bind the result of some computation to a scope without "polluting" the outer scope.

creater.createObject().让我们 {
    if (it.isCorrect && it.shouldBeLogged) {
        logger.log(it)
    }
}

// `it` is out of scope here

with

The with function is inspired by the with language construct from languages like Delphi or Visual Basic (and probably many others) where

The with keyword is a convenience provided by Delphi for referencing elements of a complex variable, such as a record or object.

myObject.colour := clRed;
myObject.size   := 23.5;
myObject.name   := 'Fred';

可以重写:

with myObject do
begin
  colour := clRed;
  size   := 23.5;
  name   := 'Fred';
end;

The equivalent Kotlin would be

with(myObject) {
    color = clRed
    size = 23.5
    name = "Fred"
}

申请

申请 was added to the stdlib relatively late in the milestone phase (M13). You can see this question from 2015 where a user asks for exactly such a function and even suggests the later to-be-used name "申请".

在第https://youtrack.jetbrains.com/issue/KT-6903期和第https://youtrack.jetbrains.com/issue/KT-6094期中,你可以看到有关命名的讨论.提出了buildinit等备选方案,但丹尼尔·沃多潘提出的申请最终获胜.

申请 is similar to with in that it can be used to initialize objects outside of the constructor. That's why, in my opinion, 申请 might as well be named with. However as with was added to the stdlib first, the Kotlin devs decided against breaking existing code and added it under a different name.

Ironically, the language Xtend provides the so-called with-operator => which basically does the same as 申请.

还包括

还包括被添加到stdlib中,甚至比申请还要晚,即在1.1版中.同样,https://youtrack.jetbrains.com/issue/KT-6903包含了讨论.该函数基本上类似于申请,只是它采用常规的lambda (T) -> Unit,而不是扩展lambda T.() -> Unit.

提议的名称包括"申请It"、"申请让我们"、"on"、"Tap"、"touch"、"peek"、"make".但"也"获胜了,因为它不会与任何关键字或其他stdlib函数冲突,而且它的用法(或多或少)读起来像英语句子.

Example

val object = creater.createObject().还包括 { it.initiliaze() }

读起来有点像

Creater,创建对象并初始化它!

其他用法读起来有点像英语句子的stdlib函数包括takeIftakeUnless,它们也是在1.1版中添加的.

Finally, the function actually has two signatures. The first one fun <R> 跑(block: () -> R): R simply takes a lambda and 跑s it. It is mostly used for assigning the result of a lambda expression to a top-level property

val logger = 跑 {
    val name = System.property("logger_name")
    Logger.create(name)
}

第二签名fun <T, R> T.跑(block: T.() -> R): R是以扩展λ为参数的扩展函数,并且由于对称原因似乎也被命名为"Run".它也"运行"lambda,但在扩展接收器的上下文中

val result = myObject.跑 {
    intitialize()
    computeResult()
}

我不知道这个命名有任何历史原因.

Kotlin相关问答推荐

如果启用了Flyway迁移,则不能具有配置属性';datources.default.架构-生成

Android Studio中的只读集合不支持操作失败的原因是什么?

当我通过媒体通知更改音乐时不要更新我的 UI

如何在 kotlin 中的数据类中为变量提供多种类型

如何使用 Mockk 模拟返回值类的 Kotlin 函数类型?

循环中的每个元素都应填充行中可用的所有可用空间

gradle 如何 Select 以-jvm结尾的库?

如何将glide显示的图像下载到设备存储中.Kotlin

parallelStream()和asSequence().asStream().parallel()之间的区别

这是什么 Kotlin 类型:(String..String?)

错误:cannot find symbol import com.gourav.news.databinding.ActivityDetailBindingImpl;

类型是什么意

无法从 XML 访问 NavHostFragment

Kotlin 有 array.indexOf 但我无法弄清楚如何做 array.indexOfBy { lambda }

在 Kotlin 中实现 (/inherit/~extend) 注解

Kotlin - 来自 KType 的 KClass<*>

Kotlin中的测试无法访问受保护(protected)的方法

类型不匹配:推断类型为 LoginActivity 但应为 LifecycleOwner

Kotlin协程无法处理异常

如何计算Kotlin中的百分比