Patrón de préstamo en Scala

Scala en profundidad demuestra el patrón de préstamo :

def readFile[T](f: File)(handler: FileInputStream => T): T = { val resource = new java.io.FileInputStream(f) try { handler(resource) } finally { resource.close() } } 

Ejemplo de uso:

 readFile(new java.io.File("test.txt")) { input => println(input.readByte) } 

Este código parece simple y claro. ¿Qué es un “antipatrón” del patrón Loaner en Scala para que sepa cómo evitarlo?

Asegúrese de que todo lo que calcule se evalúe con entusiasmo y ya no dependa del recurso. Scala hace que el cálculo perezoso sea bastante fácil. Por ejemplo, si scala.io.Source.fromFile de esta manera, puede probar

 readFile("test.txt")(_.getLines) 

Desafortunadamente, esto no funciona porque getLines es flojo (devuelve un iterador). Y Scala no tiene una buena manera de indicar qué métodos son flojos y cuáles no. Entonces solo tiene que saber (los doctores tenderán a decirle), y debe hacer el trabajo antes de regresar:

 readFile("test.txt")(_.getLines.toVector) 

En general, es un patrón muy útil. Solo asegúrate de que todos los accesos al recurso se completen antes de salir del bloque (para que no haya futuros incompletos, vals perezosos que dependan del recurso, no iteradores, no devuelva el recurso en sí, no haya transmisiones que no se hayan leído completamente, etc. ., por supuesto, cualquiera de estas cosas está bien si no dependen del recurso abierto, sino solo de una cantidad totalmente calculada en función del recurso).

Con el patrón de Préstamo, es importante saber cuándo va a usar el “bit” de código que va a llamar realmente a su recurso prestado.

Si desea devolver un futuro de un patrón de préstamo, le aconsejo que no lo cree dentro de la función que se pasa a la función de patrón de préstamo.

No escribir

 readFile("text.file")(future { doSomething }) 

pero hazlo

 future { readFile("text.file")( doSomething ) } 

lo que suelo hacer es que defino dos tipos de funciones de patrones de préstamo: sincrónico y asíncrono

Entonces en tu caso yo tendría:

 def asyncReadFile[T](f: File)(handler: FileInputStream => T): Future[T] = { future{ readFile(f)(handler) } } 

De esta forma evitas llamar a recursos cerrados. Y reutiliza su código ya probado y, con suerte, correcto de la función Sincrónica.