当我查看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是如何知道的。
答案 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
返回。 streamOut
和streamIn
也将陆续关闭。
总的来说,我们做了什么?我们基本上同时使用了2个资源,然后将其关闭。这就是您组成 use
来同时使用多个资源的方式。
答案 1 :(得分:1)
在lambda中,您可以为对象定义一个名称,因此在以下代码中input
等效于it
,streamIn
,输出等效于{{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中的扩展功能。