for-comprehension, guard 和 RandomAccessFile.readLine
for-comprehension, guard and RandomAccessFile.readLine
考虑以下几点:
有一个包含一定行数的文本文件,例如:
test.txt:
a
b
c
d
e
f
g
h
(各占一行)
然后就是下面的class用于解析:
class MyAwesomeParser
{
def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
val randomAccessFile = new RandomAccessFile(fileName, "r")
val x: IndexedSeq[String] = for
{
x <- 0 until readLines
r = randomAccessFile.readLine()
} yield r
x
}
}
测试来了:
class MyAwesomeParserTest extends WordSpec
{
"MyAwesomeParser" when {
"read" should {
"parse only specified number of lines" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 5)
assert(x.size == 5)
}
}
"MyAwesomeParser" when {
"read" should {
"parse only until end of file" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 10)
assert(x.size == 8)
}
}
}
}
第二个测试有问题。现在你当然会说,你这里少了一个守卫……好吧,好吧,如果我加上
x <- 0 until readLines if randomAccessFile.readLine != null
到实现然后它跳过几行,因为 readLine 已经消耗了该行。
r = randomAccessFile.readLine
x <- 0 until readLines if r != null
可悲的是不会工作,因为第一行必须是分配理解。
现在我想知道,是否有可能使用 for 理解循环直到给定次数或根据 readLine != null
条件停止?
我的语法有问题吗?
你可以把randomAccessFile.readLine
封装在一个Option
中,这样null
就会变成None
,value
就会变成Some(value)
。
另外,Option
可以看作是一个集合,所以可以和IndexedSeq
放在一起理解:
for {
x <- 0 until readLines
r <- Option(randomAccessFile.readLine())
} yield r
如果你想坚持你的 parse
方法,你可以只使用 getFilePointer
和 length
def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
val randomAccessFile = new RandomAccessFile(fileName, "r")
val x: IndexedSeq[String] = for
{
x <- 0 until readLines if randomAccessFile.getFilePointer < randomAccessFile.length
r = randomAccessFile.readLine()
} yield r
x
}
但是,与其重新发明轮子,我建议你直接使用 scala.io.Source
:
def parse(fileName: String, readLines: Int): Iterator[String] =
Source.fromFile(fileName).getLines.take(readLines)
考虑以下几点:
有一个包含一定行数的文本文件,例如:
test.txt: a b c d e f g h
(各占一行)
然后就是下面的class用于解析:
class MyAwesomeParser
{
def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
val randomAccessFile = new RandomAccessFile(fileName, "r")
val x: IndexedSeq[String] = for
{
x <- 0 until readLines
r = randomAccessFile.readLine()
} yield r
x
}
}
测试来了:
class MyAwesomeParserTest extends WordSpec
{
"MyAwesomeParser" when {
"read" should {
"parse only specified number of lines" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 5)
assert(x.size == 5)
}
}
"MyAwesomeParser" when {
"read" should {
"parse only until end of file" in {
val parser = new EdgeParser("")
val x = parser.parse("test.txt", 10)
assert(x.size == 8)
}
}
}
}
第二个测试有问题。现在你当然会说,你这里少了一个守卫……好吧,好吧,如果我加上
x <- 0 until readLines if randomAccessFile.readLine != null
到实现然后它跳过几行,因为 readLine 已经消耗了该行。
r = randomAccessFile.readLine
x <- 0 until readLines if r != null
可悲的是不会工作,因为第一行必须是分配理解。
现在我想知道,是否有可能使用 for 理解循环直到给定次数或根据 readLine != null
条件停止?
我的语法有问题吗?
你可以把randomAccessFile.readLine
封装在一个Option
中,这样null
就会变成None
,value
就会变成Some(value)
。
另外,Option
可以看作是一个集合,所以可以和IndexedSeq
放在一起理解:
for {
x <- 0 until readLines
r <- Option(randomAccessFile.readLine())
} yield r
如果你想坚持你的 parse
方法,你可以只使用 getFilePointer
和 length
def parse(fileName: String, readLines: Int): IndexedSeq[String] =
{
val randomAccessFile = new RandomAccessFile(fileName, "r")
val x: IndexedSeq[String] = for
{
x <- 0 until readLines if randomAccessFile.getFilePointer < randomAccessFile.length
r = randomAccessFile.readLine()
} yield r
x
}
但是,与其重新发明轮子,我建议你直接使用 scala.io.Source
:
def parse(fileName: String, readLines: Int): Iterator[String] =
Source.fromFile(fileName).getLines.take(readLines)