目前我正在编写一个从bytes.Buffer读取缓冲区的程序。它应该在找到角色e时停止阅读。但是当我使用for循环读取缓冲区时,我注意到了一些奇怪的东西。当我将字节读取作为for语句的一部分时,我得到一个无限循环(example in go playground):
b := bytes.NewBuffer([]byte("uoiea"))
for v, _ := b.ReadByte(); v != 'e'; {
println("The value is " + string(v))
}
但如果我删除它并将其放入for循环中,它就不会(example in go playground):
b := bytes.NewBuffer([]byte("uoiea"))
for ;; {
v, _ := b.ReadByte()
println("The value is " + string(v))
if v == 'e'{
break
}
}
有谁知道为什么会这样?我发现添加break表达式是一种非常难看且容易出错的解决方法。
答案 0 :(得分:4)
因为for循环的post statement为空(您只有 init语句),所以每次迭代都不会读取下一个字节(v
总是'u'
)。
以下是fixed version:
b := bytes.NewBuffer([]byte("uoiea"))
for v, _ := b.ReadByte(); v != 'e'; v, _ = b.ReadByte() {
println("The value is " + string(v))
}
正如评论中所提到的,当没有'e'
字节时,还建议检查错误以避免无限循环:
b := bytes.NewBuffer([]byte("uoiea"))
for v, e := b.ReadByte(); v != 'e' && e == nil; v, e = b.ReadByte() {
println("The value is " + string(v))
}
当缓冲区为空时, ReadBytes
会返回io.EOF
错误。
答案 1 :(得分:3)
当您进入循环时,您只读取缓冲区一次。因此mPianoRoll
的值始终为v
。您可以通过读取for循环的post语句中的下一个字节来解决它:
'u'
但是你的第二个例子实际上是更好,更难看的方式。在这样的循环中使用for v, _ := b.ReadByte(); v != 'e'; v, _ = b.ReadByte() {
// This works as long as there is an 'e' in your buffer
// Otherwise this goes to infinite loop also, as you are discarding error
并没有错。实际上,在适当时(通常在您收到break
错误时,将Read()
循环写为无条件for
循环和break
非常惯用你达到了正在读的任何一切的结束)。它导致代码更易于阅读,尤其是当有许多条件导致io.EOF
时。编写代码的惯用和首选(IMHO)方式是:
break
这与您的工作示例几乎相同。只是错误检查。但b := bytes.NewBuffer([]byte("uoiea"))
for {
v, err := b.ReadByte()
if err == io.EOF {
// End of buffer. Should always break here to avoid infinite loop.
break
}
if err != nil {
// Error other than io.EOF means something went wrong with reading.
// Should handle it appropriately. Here I'll just panic.
panic(err)
}
if v == 'e' {
break
}
println("The value is " + string(v))
}
错误检查尤为重要,否则如果缓冲区中没有io.EOF
,您将陷入无限循环。