How can I override Tie :: File in Scala?

I really like Tie :: File , which allows you to tie array of file strings. You can modify the array in any way, and when you are done with it, you untie it and change the contents of the file accordingly.

I would like to override this behavior in Scala, and this is what I still have:

 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() } 

However, the β€œstatements” defined in ArrayBuffer return different classes than mine, for example:

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

gives me immutable.Vector . I could limit the class to a very small set of predefined methods, but I thought it would be nice if I could offer all of them (foreach / map / ...).

What should I inherit, or how can I approach this problem so that I have a fluid massive interface that allows me to modify the contents of a file?

BOUNTY : To win the award, can you show a working example that CanBuildFrom uses to complete this task?

+6
source share
2 answers

Methods ending with a colon are right associative , so in your example you call +: from String with the TiedBuffer as parameter. If you want to test +: from ArrayBuffer , you can do:

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

or

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

EDIT

I missed the point in your question, see John answer to return TiedBuffer objects instead of ArrayBuffer .

EDIT2

Here is an example with CanBuildFrom . You will have to call tie manually, but to prevent the file from being bound every time the creator creates a new instance of TiedBuffer . There is still much room for improvement, for example ++ will not work, but it should get you started.

 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
source

Extending an existing collection requires the definition of a builder in a companion object such as

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

This is fully explained here:

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

As Marx Jaxell noted, the reason you get the vector is because you use the correct associative operators, otherwise the implicit builder will be selected and you will get an ArrayBuffer

+4
source

Source: https://habr.com/ru/post/892787/


All Articles