当我查看 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
返回。streamOut
和streamIn
也将陆续关闭。
那么总的来说,我们做了什么?我们基本上同时使用了 2 个资源,然后关闭了它们。这就是您编写use
以同时使用多个资源的方式。
在 lambda 中,您可以为对象定义一个名称,因此在下面的代码中,input
等效于it
,这是streamIn
,输出等效于streamOut
:
streamIn.use { input ->
streamOut.use { output ->
input.copyTo(output)
}
}
他们定义input
和output
的原因是,当您在另一个 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 中的扩展函数的更多信息。