在 Scala 中编写 read-while 循环的正确方法是啥?
Posted
技术标签:
【中文标题】在 Scala 中编写 read-while 循环的正确方法是啥?【英文标题】:What is the proper way to code a read-while loop in Scala?在 Scala 中编写 read-while 循环的正确方法是什么? 【发布时间】:2011-03-01 23:10:48 【问题描述】:在 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 风格。一方面,它是对 Java 代码的直译,没有利用 Scala 的任何优点。此外,它实际上比 Java 代码长!我真的觉得我错过了什么,但我不知道是什么。
我对 Scala 还很陌生,所以我提出这个问题是为了避免陷入在 Scala 中编写 Java 样式代码的陷阱。我对 Scala 解决此类问题的方法更感兴趣,而不是 Scala API 可能提供的用于散列文件的任何特定辅助方法。
(我提前为我在整个问题中使用的 Scala 形容词道歉。)
【问题讨论】:
我对@987654321@ 的回答可能会有所帮助。 @Rex 我会使用Iterator
而不是Stream
。毕竟,它是一次性的,不可重复使用。此外,Iterator
在此类任务中具有更好的内存性能。
@Daniel - 同意。我相信我之前使用Stream
有一个很好的理由,但我不再记得是什么(而且我认为它仍然不是真的)。无论如何,这里Iterator.continually
应该没问题。
【参考方案1】:
根据他提到的 Rex 的帖子:
Stream.continually(input.read(buffer)).takeWhile(_ != -1).foreach(md.update(buffer, 0, _))
您应该用它替换 var readLen + while ... 行,它会产生相同的结果。
正如 Rex 所说,它适用于 scala 2.8。
【讨论】:
如果 Stream 给你威力,你也可以只使用 Iterator.continually。 当我在从 Process 获得的 InputStream 上尝试它时,foreach 方法只是为第一个字符调用然后停止。当与 while 一起使用时,我得到所有数据。知道为什么吗? 如何获取从“input.read(...)”读取的字节数以在“foreach”中使用它?【参考方案2】: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
。它得到一个不断求值的表达式,创建一个无限的Stream
求值表达式。 takeWhile
是 while
条件的转换。 foreach
是 while
循环的主体。
【讨论】:
【参考方案3】:柯里化函数呢?你的 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
的方案复杂。
【讨论】:
以上是关于在 Scala 中编写 read-while 循环的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章