在Scala中编写read-while循环的正确方法是什么?

时间:2010-06-10 01:40:13

标签: scala inputstream io

在Scala中编写标准read-while循环的“正确”是什么?正确地说,我的意思是用类似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代码是正确的并且有效,但感觉非常不符合Scala-ish。首先,它是Java代码的字面翻译,充分利用了Scala的优势。而且它实际上比Java代码长!我真的觉得我错过了什么,但我无法弄清楚是什么。

我对Scala相当陌生,因此我提出的问题是避免陷入在Scala中编写Java风格代码的陷阱。我对Scala解决此类问题的方式比对Scala API提供的任何特定帮助方法更感兴趣,以便对文件进行哈希处理。

(我在此问题中提前为我的临时Scala形容词道歉。)

3 个答案:

答案 0 :(得分:28)

根据雷克斯的帖子,他提到:

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

你应该用它替换var readLen + {...}行,它会产生相同的结果。

正如Rex所说,它适用于scala 2.8。

答案 1 :(得分:8)

Rex Kerr在评论中建议如下:

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。它得到一个连续计算的表达式,创建一个计算表达式的无限StreamtakeWhile是来自while条件的翻译。 foreachwhile - 循环的主体。

答案 2 :(得分:0)

咖喱功能怎么样?你有11行Scala代码:

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

第3行的iterateStream函数可以添加到库中:

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解决方案那么复杂。