Kotlin 如何识别 "use" 函数中的 lambda 接收器



当我查看 Kotlin 中 "use" 函数的示例代码时,我通常会看到这样的东西:

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

但是,在下面的示例中,我不明白"input"从何而来,因为 input -> 似乎是一个 lambda。根据我的理解,使用 { } 中的所有内容都必须是一个表达式:

val streamIn = resources.openRawResource(rawResId)
val streamOut = FileOutputStream(destFilename)
streamIn.use { input ->
streamOut.use { output ->
input.copyTo(output)
}
}
">

input"显然指的是"streamIn"所指的同一个对象,但我不明白 Kotlin 是如何知道这一点的。

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

如果你查看签名,你会发现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 的参数。

">

input"显然指的是"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以同时使用多个资源的方式。

在 lambda 中,您可以为对象定义一个名称,因此在下面的代码中,input等效于it,这是streamIn,输出等效于streamOut

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

他们定义inputoutput的原因是,当您在另一个 lambda 块中使用 lambda 块时,您无法使用它。

use是一个扩展函数,它将任何调用它的内容作为参数。

假设此示例:

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

根据 Kotlin 的 API 文档,这是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内部,您的函数将被调用。

有关 Kotlin 中的扩展函数的更多信息。

相关内容

最新更新