代码之家  ›  专栏  ›  技术社区  ›  s1m0nw1

作用域函数apply/with/run/also/let:它们的名称来自哪里?

  •  15
  • s1m0nw1  · 技术社区  · 7 年前

    有相当多的博客帖子(如 this )标准库函数的使用 apply / with / run / also / let 这使得区分何时实际使用这些漂亮的函数变得更加容易。

    几周来,官方文件甚至最终提供了关于该主题的指导方针: https://kotlinlang.org/docs/reference/coding-conventions.html#using-scope-functions-applywithrunalsolet

    尽管如此,我认为要记住函数的 个别用例 函数名称 . 我是说,对我来说,它们似乎可以互换,为什么不能 允许 打电话 例如?

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

    4 回复  |  直到 3 年前
        1
  •  26
  •   stkent    7 年前

    这是一个 非正式的 概述这些名称是如何形成的。

    允许

    let 受到函数式编程世界的启发。根据 Wikipedia

    “let”表达式将函数定义与受限范围相关联

    在Haskell等FP语言中,您可以使用 允许 将值绑定到受限范围内的变量,如

    aaa = let y = 1+2
              z = 4+6
              in  y+z
    

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

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

    的典型用法 允许 是将一些计算的结果绑定到一个范围,而不“污染”外部范围。

    creater.createObject().let {
        if (it.isCorrect && it.shouldBeLogged) {
            logger.log(it)
        }
    }
    
    // `it` is out of scope here
    

    具有

    这个 with 该功能的灵感来自 具有 从以下语言构造语言 Delphi Visual Basic (可能还有许多其他人)在哪里

    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)相对较晚的时候添加到stdlib。你可以看到 this 2015年的一个问题是,一个用户要求提供这样一个功能,甚至建议使用后者的名称“apply”。

    在问题中 https://youtrack.jetbrains.com/issue/KT-6903 https://youtrack.jetbrains.com/issue/KT-6094 您可以看到有关命名的讨论。备选方案,如 build init 已提议但名称 申请 由丹尼尔·沃多潘提议,最终获胜。

    申请 类似于 具有 因为它可以用来初始化构造函数外部的对象。这就是为什么在我看来, 申请 还不如被命名为 具有 . 但作为 具有 是首先添加到stdlib的,Kotlin开发人员决定不破坏现有代码,并以不同的名称添加它。

    讽刺的是,Xtend语言提供了 with-operator => 基本上与 申请 .

    而且

    also 添加到stdlib的时间甚至晚于 申请 ,即在版本1.1中。再一次 https://youtrack.jetbrains.com/issue/KT-6903 包含讨论。功能基本上如下 申请 除了需要一个普通的lambda (T) -> Unit 而不是扩展lambda T.() -> Unit .

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

    实例

    val object = creater.createObject().also { it.initiliaze() }
    

    读起来有点像

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

    其他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()
    }
    

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

        2
  •  10
  •   Willi Mentzel user670265    7 年前

    我强烈建议你读一下 blog 为了理解所有这些作用域函数。

    这些博客的一些关键点:

    1. LARA函数

    enter image description here

    在每个字母的第一个字母之后,你会得到首字母缩略词LARA。

    1. 代码比较

    enter image description here

    1. 常见用例

    2. 具有

    with() 在功能上与的扩展功能版本相同 run() ,因此它非常适合 初始化并执行 . 更多 information .

        3
  •  8
  •   voddan    7 年前

    在@kirillRakhman的回答中添加:

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

    with :

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

    apply :

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

    also :

    db.users()
        .filter { it.age > 18 }
        .map { account }
        .also { log(it) }
    

    我觉得这不太好用 let 好毕竟,它取自“那些可怕的FP语言”。但我经常认为这是一种 Let's do this! 建筑如下所示,您可以将代码读为 let's print it! :

    account.map { it.owner }.sumBy {age}.let { print(it) }
    
        4
  •  0
  •   Arun Joshi    3 年前

    范围功能总结:

    允许 :用于检查空值,也优于多线程情况下的简单空值检查

    而且 :与“let”相同,但它不会将最后一行返回为“let”,而是“还”将返回调用它的对象,而“不是最后一行!”

    申请 :如果您想更改对象的属性,可以使用此函数来修改对象,并且当我们在对象的类中工作时,它使用“this”而不是“it”

    :相当于“apply”,但它不会返回调用它的对象,而是返回最后一行

    具有 :与“run”相同,但签名不同。