Как правильно кодировать цикл чтения в Scala? - PullRequest
26 голосов
/ 10 июня 2010

Каково «правильное» написание стандартного цикла чтения в Scala? Под собственно я имею в виду написанное в стиле Scala, а не в стиле Java.

Вот код, который у меня есть на Java:

MessageDigest md = MessageDigest.getInstance( "MD5" );
InputStream input = new FileInputStream( "file" );
byte[] buffer = new byte[1024];
int readLen;
while( ( readLen = input.read( buffer ) ) != -1 )
    md.update( buffer, 0, readLen );
return md.digest();

Вот код, который у меня есть в Scala:

val md = MessageDigest.getInstance( hashInfo.algorithm )
val input = new FileInputStream( "file" )
val buffer = new Array[ Byte ]( 1024 )
var readLen = 0
while( readLen != -1 )
{
    readLen = input.read( buffer )
    if( readLen != -1 )
        md.update( buffer, 0, readLen )
}
md.digest

Код Scala правильный и работает, но выглядит очень не по-скала. С одной стороны, это буквальный перевод кода Java, не использующий ни одно из преимуществ Scala. Кроме того, он на самом деле длиннее, чем код Java! Я действительно чувствую, что что-то упустил, но не могу понять, что.

Я довольно новичок в Scala, и поэтому я задаю вопрос, чтобы не попасть в ловушку написания кода в стиле Java в Scala. Меня больше интересует способ решения этой проблемы в Scala, чем какой-либо конкретный вспомогательный метод, который может быть предоставлен Scala API для хеширования файла.

(заранее прошу прощения за свои специальные прилагательные Scala в этом вопросе.)

Ответы [ 3 ]

28 голосов
/ 10 июня 2010

Основываясь на сообщении Рекса, которое он упомянул:

Stream.continually(input.read(buffer)).takeWhile(_ != -1).foreach(md.update(buffer, 0, _))

Вам следует заменить var readLen +, в то время как {...} строк на него, он дает тот же результат.

Как уже упоминал Рекс, он работает с Scala 2.8.

8 голосов
/ 10 июня 2010

Рекс Керр предлагает в своем комментарии следующее:

val md = MessageDigest.getInstance("MD5")
val input = new FileInputStream("foo.txt")
val buffer = new Array[ Byte ]( 1024 )
Stream.continually(input.read(buffer))
  .takeWhile(_ != -1)
  .foreach(md.update(buffer, 0, _))
md.digest

Ключ - Stream.continually.Он получает выражение, которое вычисляется непрерывно, создавая бесконечное Stream вычисляемого выражения.takeWhile - это перевод с while -условия.foreach - это тело while -петля.

0 голосов
/ 04 февраля 2013

А как насчет функции карри?Вы получаете 11 строк кода Scala:

val md = MessageDigest.getInstance(hashInfo.algorithm)
val input = new FileInputStream("file")
iterateStream(input){ (data, length) => 
    md.update(data, 0, length)
}
md.digest

Функция iterateStream в строке 3, которую вы можете добавить в библиотеку:

def iterateStream(input: InputStream)(f: (Array[Byte], Int) => Unit){
    val buffer = new Array[Byte](512)
    var curr = input.read(buffer)
    while(curr != -1){
        f(buffer, curr)
        curr = input.read(buffer)
    }
}

Уродливый дублированный код (гдеввод читается) попадает в библиотеку, хорошо протестирован и спрятан от программиста.Мне кажется, что первый блок кода менее сложен, чем решение Iterator.continually.

...