Stackoverflow when use bufferedInputStream as a tr

2019-06-24 05:57发布

I am trying to solve a problem given by the Book "Scala for the Impatient", which asked to implement java's BufferedInputStream as a trait. Here is my implementation,

trait Buffering {           
    this:InputStream =>
        private[this] val bis = {
            new JavaBufferedInputStream(this)
        }
        override def read = bis.read
        override def read(byte:Array[Byte], off:Int, len:Int) = bis.read(byte, off, len)
        override def available = bis.available
        override def close() {
            bis.close
        }
        override def skip(n:Long) = bis.skip(n)
}

def main(args:Array[String]) {
    val bfis = new FileInputStream(new File("foo.txt")) with Buffering
    println(bfis.read)
    bfis.close
}

But this give me a java stackoverflow error, so what's wrong with it? Thanks!

标签: scala traits
3条回答
我想做一个坏孩纸
2楼-- · 2019-06-24 06:02

I have been going through "Scala for the Impatient". Here is what I have as a solution to exercise 8 in chapter 10:

import java.io._

object BufferedInputStream extends App {

  trait Buffering {
    this: FileInputStream =>
    val br = new BufferedInputStream(this)
  }

  def bufferedReader(f: String): Unit = {
    val fis = new FileInputStream(f) with Buffering
    var c = 0
    var blen = 8192
    var len = 0
    var b = new Array[Byte](blen)
    while (fis.br.available > 0) {
      if (fis.br.available > blen) len = blen
      else len = fis.br.available
      c = fis.br.read(b, 0, len)
      if (c == -1) return
      print((for (i <- 0 to (c - 1)) yield b(i).toChar).mkString)
    }
    fis.br.close
    fis.close
  }

  bufferedReader("webpagexample")

}
查看更多
老娘就宠你
3楼-- · 2019-06-24 06:09

Maybe this is the answer. Just maybe from what i understood.

trait Buffering extends InputStream{
abstract override def read()=
{
    println("Hello");
    super.read()
}
}
val t = new ByteArrayInputStream("hello".getBytes()) with Buffering
查看更多
乱世女痞
4楼-- · 2019-06-24 06:25

It looks like you are getting a stack overflow where you don't expect one. The key to troubleshoot these is to look at the repeating cycle of the stack trace. It usually points to what is repeatedly allocating frames. Here it will show something like that:

at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)

So reading from bottom to top, it looks like your read(byte, ...) is calling bis.read(byte, ...) which is calling BufferedInputStream.read which is then calling your read(byte, ...) again.

It would appear that new BufferedInputStream(this) is calling read on the underlying InputStream but since the underlying this is your object that then delegates calls on bis we have infinite recursion.

I'm guessing that the author wants you to use the abstract override stackable modifications pattern where you can use super to refer to the right read method.

查看更多
登录 后发表回答