范围函数适用于/带有/运行/同时/允许:名称从何而来? [英] Scope functions apply/with/run/also/let: Where do the names come from?

查看:74
本文介绍了范围函数适用于/带有/运行/同时/允许:名称从何而来?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有很多博客文章(例如 this ),了解标准库函数apply/with/run/also/let的用法,这使得区分何时实际使用哪些漂亮库变得更加容易功能.

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

尽管如此,我认为用函数名称记住该函数的个别用例非常困难.我的意思是,对我来说它们似乎是可互换的,为什么let例如不被称为run?

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.

let 受函数式编程世界的启发.根据维基百科

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

a "let" expression associates a function definition with a restricted scope

在Haskell这样的FP语言中,您可以使用let将值绑定到像这样的受限范围内的变量

In FP languages like Haskell you can use let to bind values to variables in a restricted scope like so

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

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

The equivalent (albeit overly complicated) code in Kotlin would be

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

let的典型用法是将某些计算的结果绑定到一个范围,而不会污染"外部范围.

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

creater.createObject().let {
    if (it.isCorrect && it.shouldBeLogged) {
        logger.log(it)
    }
}

// `it` is out of scope here

with

with 函数是受with语言结构,例如 Delphi

with

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

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

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;

等效的Kotlin为

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

应用

apply 相对较晚地添加到了stdlib中在里程碑阶段(M13).您可以从2015年开始看到问题,其中用户要求使用确切的功能,甚至建议以后使用名称为应用".

apply

apply 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 "apply".

在问题中 https://youtrack.jetbrains.com/issue/KT-6903 https://youtrack.jetbrains.com/issue/KT-6094 您可以看到有关命名的讨论.提出了诸如buildinit之类的替代方案,但最终由Daniil Vodopian提出的名称apply获得了胜利.

In the issues https://youtrack.jetbrains.com/issue/KT-6903 and https://youtrack.jetbrains.com/issue/KT-6094 you can see discussions of the naming. Alternatives like build and init were proposed but the name apply, proposed by Daniil Vodopian, ultimately won.

applywith相似,因为它可用于初始化构造函数之外的对象.在我看来,这就是为什么apply可能也被命名为with的原因.但是,由于with首先被添加到stdlib中,因此Kotlin开发人员决定不破坏现有代码,而是以其他名称添加它.

apply is similar to with in that it can be used to initialize objects outside of the constructor. That's why, in my opinion, apply 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.

具有讽刺意味的是,语言Xtend提供了所谓的 with-operator => 基本上与apply相同.

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

also 甚至在以后添加到了stdlib比apply,即在1.1版中.同样, https://youtrack.jetbrains.com/issue/KT-6903 包含讨论.该功能基本上类似于apply,除了它使用常规lambda (T) -> Unit而不是扩展lambda T.() -> Unit.

also was added to the stdlib even later than apply, namely in version 1.1. Again, https://youtrack.jetbrains.com/issue/KT-6903 contains the discussion. The function is basically like apply except that it takes a regular lambda (T) -> Unit instead of an extension lambda T.() -> Unit.

在提议的名称中,有"applyIt","applyLet","on","tap","touch","peek","make".但是也"获胜,因为它不会与任何关键字或其他stdlib函数发生冲突,并且其用法(或多或少)读起来像英语句子.

Among the proposed names were "applyIt", "applyLet", "on", "tap", "touch", "peek", "make". But "also" won as it doesn't collide with any keywords or other stdlib functions and its usages (more or less) read like English sentences.

示例

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

读起来有点像

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

其用法读起来有点像英语句子的其他stdlib函数包括 takeIf takeUnless 在1.1版中也添加了.

Other stdlib functions whose usages read a bit like English sentences include takeIf and takeUnless which also were added in version 1.1.

最后, run 函数实际上有两个签名.第一个fun <R> run(block: () -> R): R只需输入一个lambda,然后运行.它主要用于将lambda表达式的结果分配给顶级属性

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

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

第二个签名fun <T, R> T.run(block: T.() -> R): R是一个扩展函数,它以扩展lambda作为参数,并且出于对称性的原因,似乎也被命名为"run".它还可以运行" lambda,但要在扩展接收方的上下文中

The second signature fun <T, R> T.run(block: T.() -> R): R is an extension function which takes an extension lambda as parameter and seems to also be named "run" for symmetry reasons. It also "runs" a lambda but in the context of an extension receiver

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

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

I'm not aware of any historical reasons for the naming.

这篇关于范围函数适用于/带有/运行/同时/允许:名称从何而来?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆