2016-11-15 7 views
1

Рассмотрим следующий пример:для-понимания, охраны и RandomAccessFile.readLine

Существует текстовый файл с определенным количеством строк, например:

test.txt: б с д е е г ч

(каждая в там собственной линии)

Тогда есть следующий класс, используемый для синтаксического анализа:

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 

не будет работать печально, так как первая строка должна быть назначением для понимания.

Теперь интересно, возможно ли это, если вы понимаете, что цикл должен быть задан до заданного количества раз ИЛИ останавливаться раньше, чем на основании этого условия readLine != null?

Является ли мой синтаксис только сломанным?

ответ

2

Вы можете инкапсулировать randomAccessFile.readLine в Option, так что null будет изменен на None и value к Some(value).

Кроме того, Option можно рассматривать как набор, так что вы можете поместить его в то же самое для понимания как IndexedSeq:

for { 
    x <- 0 until readLines 
    r <- Option(randomAccessFile.readLine()) 
} yield r 
3

Если вы хотите придерживаться своего метода 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) 
+0

Ах, дерьмо .. Я попытался привести небольшой пример, но мне не нужна работа по моей конкретной проблеме, а скорее общее решение – Sorona