这里是一个非官方的概述这些名字的由来。
让
let 受到函数式编程世界的启发。根据Wikipedia
“let”表达式将函数定义与受限范围相关联
在像 Haskell 这样的 FP 语言中,您可以使用 let 将值绑定到像这样的受限范围内的变量
aaa = let y = 1+2
z = 4+6
in y+z
Kotlin 中的等效代码(尽管过于复杂)是
fun aaa() = (1+2).let { y ->
(4+6).let { z ->
y + z
}
}
let 的典型用法是将某些计算的结果绑定到一个范围,而不会“污染”外部范围。
creater.createObject().let {
if (it.isCorrect && it.shouldBeLogged) {
logger.log(it)
}
}
// `it` is out of scope here
与
with 函数的灵感来自于 Delphi 或 Visual Basic(可能还有许多其他语言)等语言的 with 语言结构
with关键字是Delphi提供的方便引用
复杂变量的元素,例如记录或对象。
myObject.colour := clRed;
myObject.size := 23.5;
myObject.name := 'Fred';
可以改写:
with myObject do
begin
colour := clRed;
size := 23.5;
name := 'Fred';
end;
等效的 Kotlin 将是
with(myObject) {
color = clRed
size = 23.5
name = "Fred"
}
申请
apply 在里程碑阶段 (M13) 相对较晚的时候被添加到标准库中。您可以看到 2015 年的 this 问题,用户要求正是这样的功能,甚至建议后来使用的名称“应用”。
在https://youtrack.jetbrains.com/issue/KT-6903 和https://youtrack.jetbrains.com/issue/KT-6094 问题中,您可以看到有关命名的讨论。有人提出了像 build 和 init 这样的替代方案,但由 Daniil Vodopian 提出的名称 apply 最终获胜。
apply 与with 相似之处在于它可以用于在构造函数之外初始化对象。这就是为什么,在我看来,apply 还不如命名为with。然而,由于with 首先被添加到标准库中,Kotlin 开发人员决定不破坏现有代码并以不同的名称添加它。
具有讽刺意味的是,Xtend 语言提供了所谓的with-operator =>,它与apply 基本相同。
还有
also 被添加到 stdlib 甚至比apply 更晚,即在版本 1.1 中。同样,https://youtrack.jetbrains.com/issue/KT-6903 包含讨论。该函数与apply 基本相似,不同之处在于它采用常规 lambda (T) -> Unit 而不是扩展 lambda T.() -> Unit。
建议的名称包括“applyIt”、“applyLet”、“on”、“tap”、“touch”、“peek”、“make”。但是“also”赢了,因为它不会与任何关键字或其他 stdlib 函数发生冲突,而且它的用法(或多或少)读起来像英文句子。
例子
val object = creater.createObject().also { it.initiliaze() }
有点像
创建者,创建对象并也初始化它!
其他用法读起来有点像英文句子的stdlib函数包括takeIf和takeUnless,它们也在1.1版中添加。
运行
最后,run 函数实际上有两个签名。第一个 fun <R> run(block: () -> R): R 只需要一个 lambda 并运行它。它主要用于将 lambda 表达式的结果分配给顶级属性
val logger = run {
val name = System.property("logger_name")
Logger.create(name)
}
第二个签名fun <T, R> T.run(block: T.() -> R): R 是一个扩展函数,它以扩展 lambda 作为参数,并且出于对称原因似乎也被命名为“run”。它还“运行”一个 lambda,但在扩展接收器的上下文中
val result = myObject.run {
intitialize()
computeResult()
}
我不知道命名的任何历史原因。