Kotlin有很好的包装和快捷方式,但有时我会被发现不理解它们。
我有一个简化的代码:
class PipeSeparatedItemsReader (private val filePath: Path) : ItemsReader {
override fun readItems(): Sequence<ItemEntry> {
return filePath.useLines { lines ->
lines.map { ItemEntry("A","B","C","D",) }
}
}
然后我有:
val itemsPath = Path(...).resolve()
val itemsReader = PipeSeparatedItemsReader(itemsPath)
for (itemEntry in itemsReader.readItems())
updateItem(itemEntry)
// I have also tried itemsReader.readItems().forEach { ... }
这很简单——我希望这段代码能给我一个序列,打开一个文件,读取行,解析它们,并给出ItemEntry
s,用完后关闭文件。
然而,我得到的是IOException("Stream closed")
。
不知怎的,即使在读取第一个项目(我已经调试过(之前,在Kotlin的包装器中的某个地方,reader.in
也变成了null,所以在hasNext()
中抛出了这个异常。
我在这里看到了一个类似的问题:Kotlin从不同的InputStream链接多个序列?
其中包括许多Java样板,我希望避免使用这些样板。
我应该如何使用Path.useLines()
对此序列进行编码
每个Kotlin助手都有"使用";在name中关闭您传递的lambda末尾的底层资源(至少据我所知,这是stdlib中的约定(。最常见的例子是AutoCloseable.use.
Path.useLines扩展也不例外:
调用块回调,为其提供该文件中所有行的序列,并在处理完成后关闭读取器[强调矿]
这意味着一旦块完成,useLines
就会关闭行序列,因此您无法从中返回延迟序列,因为在useLines
函数返回后您无法使用它。
因此,如果要返回一个行序列供以后使用,则不能直接返回useLines
的转换序列。序列实际上无法检测某人何时使用它们,因此useLines
需要lambda来给出"0";"范围";或";寿命;到序列,并知道何时关闭底层读取器。
如果您想包装它,您有两个主要选项:要么拆分序列操作和关闭操作(使PipeSeparatedItemsReader
可关闭(,要么使用lambda以与useLines
相同的方式处理readItems()
中的内容。