Scala in Depth演示了Loaner模式:
def readFile[T](f: File)(handler: FileInputStream => T): T = { val resource = new java.io.FileInputStream(f) try { handler(resource) } finally { resource.close() } }
用法示例:
readFile(new java.io.File("test.txt")) { input => println(input.readByte) }
此代码看似简单明了.什么是Scala中Loaner模式的"反模式",以便我知道如何避免它?
使用Loan模式,重要的是要知道实际调用您的借用资源的代码的"位"何时将使用它.
如果你想从贷款模式中返回未来,我建议不要在传递给贷款模式函数的函数内创建它.
别写了
readFile("text.file")(future { doSomething })
但是:
future { readFile("text.file")( doSomething ) }
我通常做的是定义两种类型的贷款模式功能:同步和异步
所以在你的情况下我会:
def asyncReadFile[T](f: File)(handler: FileInputStream => T): Future[T] = { future{ readFile(f)(handler) } }
这样就可以避免调用封闭资源.并且您重复使用已经过测试且希望正确的同步功能代码.
确保您计算的任何内容都得到热切评估,不再依赖于资源.Scala使得懒惰计算相当容易.例如,如果你scala.io.Source.fromFile
以这种方式包装,你可能会尝试
readFile("test.txt")(_.getLines)
不幸的是,这不起作用,因为getLines
是懒惰的(返回迭代器).并且Scala没有任何好的方法来指出哪些方法是懒惰的,哪些方法不是.所以你必须知道(文档会倾向于告诉你),你必须在返回之前完成工作:
readFile("test.txt")(_.getLines.toVector)
总的来说,这是一个非常有用的模式.只需确保在退出块之前完成对资源的所有访问(因此没有未完成的未来,没有依赖于资源的延迟val,没有迭代器,没有返回资源本身,没有完全读取的流,等等当然,如果它们不依赖于开放资源而只依赖于基于资源的一些完全计算的数量,那么这些东西中的任何一个都是可以的.