当从byte.Buffer读取时,为什么我会得到一个永无止境的循环

时间:2016-07-11 12:42:13

标签: go

目前我正在编写一个从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表达式是一种非常难看且容易出错的解决方法。

2 个答案:

答案 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,您将陷入无限循环。