在finally块中尝试关闭Source.fromURL时出现问题

时间:2017-10-18 00:26:22

标签: scala

以下代码段工作正常:

def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
  try { f(closeable) } finally { closeable.close() }

def loadDictionaryFromNet():List[String] =
  using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toList)

  val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter))

但是当我尝试将类型更改为Seq[String]时,如下所示:

def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
  try { f(closeable) } finally { closeable.close() }

def loadDictionaryFromNet():Seq[String] =
  using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toSeq)

  val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter))

然后抛出以下异常:

Exception in thread "main" java.io.IOException: stream is closed
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(HttpURLConnection.java:3348)
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3373)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    ... 

此外,当我将类型更改为IndexedSeq时,它再次有效。

它“感觉”像toSeq实际上会产生一些部分懒惰的流,它不能立即完全消耗,但有一些延迟。

你能解释一下发生了什么吗?

1 个答案:

答案 0 :(得分:1)

确实你是对的。让我们从Source.fromURL开始追踪它:

  1. Source.fromURL =&gt; scala.io.BufferedSource
  2. BufferedSource.getLines =&gt; BufferedLineIterator
  3. BufferedLineIterator.toSeq 调用
  4. scala.collection.TraversableOnce
  5. TraversableOnce将方法toSeq实现为:def toSeq: Seq[A] = toStream
  6. toStream的实施取自课程Iterator
  7. 实施如下:

    def toStream: Stream[A] =
      if (self.hasNext) Stream.cons(self.next(), self.toStream)
      else Stream.empty[A]
    
    P P,相当一段旅程。是的,你最终构建了一个懒惰的流,因此你得到了你在问题中提到的异常。