Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lambda 作用域函数apply/with/run/allow/let:名称来自哪里?_Lambda_Kotlin_Higher Order Functions_Scoping - Fatal编程技术网

Lambda 作用域函数apply/with/run/allow/let:名称来自哪里?

Lambda 作用域函数apply/with/run/allow/let:名称来自哪里?,lambda,kotlin,higher-order-functions,scoping,Lambda,Kotlin,Higher Order Functions,Scoping,有相当多的博客文章(如)介绍了标准库函数的用法apply/with/run/也可以使用/let,这使得区分何时实际使用那些漂亮的函数变得更容易 几周来,官方文件甚至最终提供了关于该主题的指导方针: 然而,我认为通过函数名来记忆函数的个别用例是相当困难的。我的意思是,对我来说,它们似乎是可以互换的,比如说,let为什么不被称为run 有什么建议吗?我认为这些名字没有很好的表现力,这使得一开始很难看出它们之间的区别。这里是一个非官方的概述,说明这些名字是如何形成的 让 受到函数式编程世界的启发。据

有相当多的博客文章(如)介绍了标准库函数的用法
apply
/
with
/
run
/
也可以使用
/
let
,这使得区分何时实际使用那些漂亮的函数变得更容易

几周来,官方文件甚至最终提供了关于该主题的指导方针:

然而,我认为通过函数名来记忆函数的个别用例是相当困难的。我的意思是,对我来说,它们似乎是可以互换的,比如说,
let
为什么不被称为
run


有什么建议吗?我认为这些名字没有很好的表现力,这使得一开始很难看出它们之间的区别。

这里是一个非官方的概述,说明这些名字是如何形成的

让 受到函数式编程世界的启发。据

“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
具有 该函数的灵感来源于
语言结构,这些语言来自或(可能还有许多其他)where等语言

with关键字是Delphi为引用提供的便利 复杂变量的元素,如记录或对象

myObject.colour := clRed;
myObject.size   := 23.5;
myObject.name   := 'Fred';
可以重写:

with myObject do
begin
  colour := clRed;
  size   := 23.5;
  name   := 'Fred';
end;
与科特林相当的是

with(myObject) {
    color = clRed
    size = 23.5
    name = "Fred"
}
应用 在里程碑阶段(M13)相对较晚的时候添加到stdlib。你们可以看到2015年的一个问题,用户要求使用这样一个函数,甚至建议使用后面的名称“apply”

在问题中,您可以看到有关命名的讨论。像
build
init
这样的备选方案被提出,但丹尼尔·沃多潘提出的名称
apply
,最终获胜

apply
with
类似,因为它可以用于初始化构造函数外部的对象。这就是为什么在我看来,
apply
也可以被命名为
with
。然而,由于stdlib中首先添加了
with
,Kotlin开发人员决定不破坏现有代码,并以不同的名称添加了它

具有讽刺意味的是,Xtend语言提供了所谓的

也 添加到stdlib的时间甚至晚于
apply
,即1.1版。同样,包含讨论内容。该函数基本上类似于
apply
,不同的是它采用常规的lambda
(T)->单元
,而不是扩展lambda
T.()->单元

拟议名称包括“applyIt”、“applyIt”、“on”、“tap”、“touch”、“peek”、“make”。但“也”赢了,因为它不会与任何关键字或其他stdlib函数发生冲突,而且它的用法(或多或少)读起来像英语句子

范例

val object = creater.createObject().also { it.initiliaze() }
读起来有点像

Creater,创建对象并初始化它

其他stdlib函数,其用法读起来有点像英语句子,包括,也被添加到1.1版中

跑 最后,函数实际上有两个签名。第一个
fun run(block:()->R):R
只需取一个lambda并运行它。它主要用于将lambda表达式的结果指定给顶级属性

val logger = run {
    val name = System.property("logger_name")
    Logger.create(name)
}
第二个签名
fun T.run(block:T.()->R):R
是一个扩展函数,它以扩展lambda为参数,出于对称性原因,似乎也被命名为“run”。它还“运行”一个lambda,但在扩展接收器的上下文中

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

我不知道命名的任何历史原因。

在@kirillRakhman的答案中添加:

命名过程的一个主要部分是(仍然是)在主要用例中流畅的阅读体验

with(database) {
    open()
    send()
    close()
}
应用

val v = View().apply {
    width = 3.0
    height = 4.0
    register(this)
}
同时

db.users()
    .filter { it.age > 18 }
    .map { account }
    .also { log(it) }
我知道它对
不起作用,那就让
好了。毕竟,它取自“那些可怕的FP语言”。但我经常认为这是一种
让我们这样做吧构造。如下图所示,您可以将代码读为
,让我们打印它

account.map { it.owner }.sumBy {age}.let { print(it) }

为了理解所有这些作用域函数,我强烈建议阅读本文

这些博客的一些关键点:

  • LARA功能
  • 在每个字母的第一个字母之后,你会得到首字母缩写“LARA”

  • 代码比较
  • 常见用例

    • 对象-let()
    • -也()
    • -运行()
    • 对于分配-应用()

  • with()
    在功能上与
    run()
    的扩展函数版本相同,因此它非常适合的用例。更多。

    这些都是非常情景化的功能。你可以在需要的时候用它们来记住它们。例如:我想知道以后如何继续?。使用nullables,我发现
    let
    。我是当场学会的。与
    或“还”的
    相同。一旦你知道它们的存在,当你知道有些东西但你不记得是什么东西时,你就会陷入这种情况。多次访问文档将确保您将来了解它们。至少我是这样做的这对我来说也不是什么问题。我总是知道其中一个可以在特定情况下使用。但问题是,函数名并不能真正说明它们真正的功能。好吧,你知道编程中最难的事情……不久前,当你回答一个以前和现在都被问到的问题时,我大惊小怪