Scala';s的方式;而";循环

Scala';s的方式;而";循环,scala,Scala,如果我有这个 val rdr = new InputStreamReader(intStr) val buffer = Array[Char](1024) val stWr = new StringWriter() 我想这样做: //straightforward var n = 0 while ({ n = rdr read buffer; n != -1 }) { stWr write (buffer, 0, n) } 与前一种方法相比,我更倾向于使用Scala的惯用方法: //l

如果我有这个

val rdr = new InputStreamReader(intStr)
val buffer = Array[Char](1024)
val stWr = new StringWriter()
我想这样做:

//straightforward

var n = 0
while ({ n = rdr read buffer; n != -1 }) {
  stWr write (buffer, 0, n)
}
与前一种方法相比,我更倾向于使用Scala的惯用方法:

//looks better, more idiomatic?
Stream.continually(rdr read buffer) takeWhile (_ != -1) foreach { x =>
  stWr write (buffer, 0, x)
}

另外,我也不确定“x”是指读取的字节数(在“foreach”中),所以我不确定这两种方法是否完全等效。

这更为惯用,它们并不等效,但我相信这是偶然的,因为
while
循环中存在一个bug(请参见下文进行更正)。不过,您的Scala风格有点不对劲——您在这行代码中使用了太多中缀符号,因为它有很多链接,所以您应该坚持使用点符号。也只在需要时使用花括号,否则使用圆括号。所以

Stream.continually(isr read buffer).takeWhile(_ != -1)
.foreach(x => sw write (buffer, 0, x))
但是,当涉及到由于没有明确的上限而需要
while
类行为的代码时,如果使用
while
循环(很多Scala代码本身使用
while
循环),这并不是世界末日。问题在于应避免的
var
。然而,对于优化的代码,有时必须使用
var
。因此,在我们纠正了您的风格(和错误)之后,while也可以:

var n = isr read buffer
while (n != -1) {
  sw write (buffer, 0, n)
  n = isr read buffer
}
错误是你在写之前读了两遍。我们也可以这样修复它:

var n: Int = _
while ({
  n = isr read buffer
  n != -1 
}) {
  sw write (buffer, 0, n)
}

最后一点,我实际上会对
read
write
方法使用点符号,但这是一个品味问题,所以我把它作为中缀。我的论点是,我只在使用中缀符号的方法时才使用中缀符号,就好像它应该是一个运算符一样——但这只是我的观点。

更惯用的解决方案是使用尾部递归方法,而不是while循环。这也将比使用
流更有效。持续

@scala.annotation.tailrec
def readAll: Unit = {
  val n = rdr.read(buffer)
  if (n != -1) {
    stWr.write(buffer, 0, n)
    readAll
  }
}
readAll

在内部,Scala将其重写为while循环。与while循环相比,这个循环更为惯用,因为它允许我们在大多数地方使用
val
,而不是
var
。例如,这里的
n
可以是
val
。更复杂的示例将有方法参数,这些参数可以填充循环中更新的变量的角色。

那么底线是什么?问题不是关于“{”over”()和使用点符号。我使用它们是因为我喜欢。问题是关于“while”循环。好的,底线是使用
Stream.continuously
更为惯用,但即使是高级Scala团队也可能不会在代码评审中被选中。你会被选中的是不正确的样式,比如不必要的
{}
,使用
,以及过度使用中缀符号。使用while循环并不完美,但相对于不正确的样式来说微不足道。还有一点……while循环对于需要优化的代码来说可能稍微快一些,更好一些,因为
方式将产生更深的堆栈(可能还有堆上的一个附加对象,但我有一段时间没有读
流的代码了(双关语)高级开发人员这样的代码审查从何而来?@AlexanderSupertramp(根据个人经验)。我从未见过使用while循环高阶函数而被拒绝的代码。此外,我从未见过格式错误的代码通过代码审查。事实上,使用Sonatype工具进行自动样式检查的公司ld实际上使推送样式错误的代码变得不可能。您的命名没有遵循正确的约定。看起来您恢复了我的编辑。请使用(按质量顺序)a)反映业务逻辑或b)的名称类型的小写字母或类型的c)初始值。当有人阅读您的代码时,他们将不知道值是什么,除非他们阅读声明,从而导致不必要的冲突和认知。@samthebest,他们确实遵循了正确的约定。您考虑得太多了。请提供理由,而不是j只能说你不同意。谷歌“InputStreamReader示例”并找到一个使用
rdr
的页面。oracle教程(即关于此类问题的圣经)使用
isr
类似于
StringWriter
…如果谷歌的例子你看不到
stWr
,你会看到
sw
@samthebest,这并不意味着stWr是不正确的,每个人都必须使用sw而不是stWr。这不是一个规则,这是一个不严格的建议。我再说一遍:你想得太多了但是,严格来说,该方法的主体被编译为“while循环”,因此您还有一个额外的方法调用。事实上,Scala中的尾部递归通过覆盖操作堆栈来工作。在这个用例中,我怀疑它是否重要,但总的来说,说性能将与while循环相同是错误的。