2011-07-14 9 views
6

realmente me gusta Tie::File, lo que le permite tie una serie de líneas de un archivo. Puede modificar la matriz de cualquier manera, y cuando haya terminado con ella, untie, y el contenido del archivo se modifica en consecuencia.¿Cómo podría volver a implementar Tie :: File en Scala?

me gustaría volver a implementar este tipo de comportamiento en Scala, y esto es lo que tengo hasta ahora:

class TiedBuffer(val file:File) extends ArrayBuffer[String] { 

    tieFile 

    def untie = { 
     val writer = new PrintStream(new FileOutputStream(file)) 
     this.foreach(e => writer.println(e)) 
     writer.close 
     this 
    } 

    private def tieFile = this ++= scala.io.Source.fromFile(file).getLines() 
} 

Sin embargo, los "operadores" definidos en el ArrayBuffer regresan varias clases, diferentes a la mía, por ejemplo:

println((new TiedBuffer(somefile) +: "line0").getClass) 

me da immutable.Vector. Podría limitar la clase a un conjunto muy pequeño de métodos predefinidos, pero pensé que sería bueno si pudiera ofrecerlos a todos (foreach/map/...).

¿Qué debería heredar de, o cómo debería abordar este problema de modo que tenga una interfaz de tipo array de líquidos, lo que me permite modificar el contenido de un archivo?

BOUNTY: para ganar la recompensa, se puede mostrar un ejemplo que hace uso de CanBuildFrom para realizar esta tarea?

+0

Para que lo sepas, Tie :: File en realidad es más compleja de lo que usted muestra aquí.No solo lee el archivo cuando lo ata y lo escribe cuando lo desata. Lee y escribe el archivo mientras trabaja con la matriz (con algunas optimizaciones para mejorar el rendimiento). Pero incluso una implementación básica como esta aún sería útil. – cjm

+0

@cjm, lo sé, por supuesto. Tie :: File es mucho más complejo que lo que muestro aquí. Pero quería que las personas que están leyendo esto entiendan claramente lo que sucede y por qué este módulo es útil. – Senthess

Respuesta

4

Los métodos que terminan con dos puntos son right associative, por lo que en el ejemplo está llamando a +: de String con un parámetro TiedBuffer. Si desea probar +: de ArrayBuffer que puede hacer:

println((new TiedBuffer(somefile).+:("line0")).getClass) 

o

println(("line0" +: new TiedBuffer(somefile)).getClass) 

EDITAR

me perdí el momento de su pregunta, veo de John answer para volver TiedBuffer objetos en lugar de ArrayBuffer.

Edit2

Aquí se muestra un ejemplo con CanBuildFrom. Tendrá que llamar tie manualmente, aunque para evitar que el archivo que estar atado cada vez que el constructor de crear una nueva instancia TiedBuffer. Todavía hay mucho margen de mejora, por ejemplo, ++ no funcionará pero debería comenzar.

import collection.generic.CanBuildFrom 
import collection.mutable._ 
import java.io.{PrintStream, FileOutputStream, File} 

class TiedBuffer(val file: File) extends ArrayBuffer[String] 
           with BufferLike[String, TiedBuffer] 
           with IndexedSeqOptimized[String, TiedBuffer] { 

    def tie = { 
    clear 
    this ++= scala.io.Source.fromFile(file).getLines() 
    } 

    def untie = { 
    val writer = new PrintStream(new FileOutputStream(file)) 
    this.foreach(e => writer.println(e)) 
    writer.close 
    this 
    } 

    override def newBuilder: Builder[String, TiedBuffer] = 
    new ArrayBuffer mapResult { 
     x: Seq[String] => (new TiedBuffer(file) ++= x) 
    } 
} 

object TiedBuffer { 
    implicit def canBuildFrom: CanBuildFrom[TiedBuffer, String, TiedBuffer] = 
    new CanBuildFrom[TiedBuffer, String, TiedBuffer] { 
     def apply(): Builder[String, TiedBuffer] = 
     throw new RuntimeException("Cannot create a new TiedBuffer from scratch") 

     def apply(from: TiedBuffer): Builder[String, TiedBuffer] = from.newBuilder 
    } 
} 
4

La extensión de la colección existente requiere la definición de un constructor en un objeto acompañante como

object TiedBuffer { 
    implict def canBuildFrom[T] = new CanBuildFrom[TiedBuffer[T],T,TiedBuffer[T]] { ... } 
} 

Esto se explica completamente aquí:

http://www.scala-lang.org/docu/files/collections-api/collections-impl.html

Como se ha señalado por Marx Jayxcela, la razón usted está obteniendo un Vector es que está utilizando un operador asociativo correcto; de lo contrario, se seleccionaría un generador implícito y lo haría obtener una ArrayBuffer

Cuestiones relacionadas