Kotlin如何在“使用”功能中识别Lambda接收器

时间:2019-10-02 05:51:55

标签: kotlin

当我查看Kotlin中“使用”功能的示例代码时,通常会看到类似这样的内容:

private fun readFirstLine(): String {
    BufferedReader(FileReader("test.file")).use { return it.readLine() }
}

但是,在下面的示例中,由于输入->似乎是lambda,因此我无法理解“输入”的来源。据我了解,使用{}中的所有内容都必须是一个表达式:

val streamIn = resources.openRawResource(rawResId)
val streamOut = FileOutputStream(destFilename)

streamIn.use { input ->
    streamOut.use { output ->
        input.copyTo(output)
    }
}

“输入”显然是指与“ streamIn”所指的同一对象,但我不知道Kotlin是如何知道的。

3 个答案:

答案 0 :(得分:2)

  

使用{}中的所有内容都必须是表达式

如果您查看signature,您会发现use带有(T) -> R函数,因此,实际上,任何接受可闭合事物作为参数的函数/ lambda都可以是传递给它。

消除了这种误解之后,让我们看看问题代码在做什么。

streamIn.use { input ->
    streamOut.use { output ->
        input.copyTo(output)
    }
}

首先我们看到streamIn.use {,这意味着我们将对streamIn进行操作,然后将其关闭。从现在起streamIn将被称为input。然后是streamOut.use {,表示我们也将使用streamOut来完成工作,然后将其关闭,从现在开始,我们将其称为output

  

我不明白“输入”的来源

基本上,就像您的第一个代码段一样,为it命名。由于我们在此处嵌套了lambda,因此无法使用it来引用两个lambda的参数。

  

“输入”显然是指与“ streamIn”所指的同一对象,但我不知道Kotlin是如何知道的。

这是因为在use的实现中,可能会有这样的一行:

return block(this)

block是您传递给use的lambda参数,而this是调用use的对象。由于input是lambda的参数,因此它引用了this

现在,我们已经声明我们将使用两种资源,它们将如何处理? input.copyTo(output)copyTo返回的内容将由streamOut.use返回,而streamIn.use返回。 streamOutstreamIn也将陆续关闭。

总的来说,我们做了什么?我们基本上同时使用了2个资源,然后将其关闭。这就是您组成 use来同时使用多个资源的方式。

答案 1 :(得分:1)

在lambda中,您可以为对象定义一个名称,因此在以下代码中input等效于itstreamIn,输出等效于{{1} }:

streamOut

他们定义streamIn.use { input -> streamOut.use { output -> input.copyTo(output) } } input的原因是,当您在另一个lambda块中使用lambda块时,您将无法使用它。

答案 2 :(得分:0)

use扩展功能,它将调用它的内容作为参数。

假设这个例子:

file.bufferedReader().use{
   println(it.readText()) // it is actually that object that calls `use`
}

根据Kotlin的API docs,这是use的架构:

inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R

在我的示例中,bufferedReader是一个可关闭的类。

编写somethingClosable.use { }时,实际上是在向其传递一个lambda函数,例如:

fun <T, R> function(t: T): R {
   // use T and return an R
}

somethingClosable.use(function)

use内部,将调用您的函数。

More info关于Kotlin中的扩展功能。