【问题标题】:Why am I getting an never ending loop when reading from a byte.Buffer为什么从 byte.Buffer 读取时我得到一个永无止境的循环
【发布时间】:2016-11-13 10:01:41
【问题描述】:

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

【问题讨论】:

    标签: go


    【解决方案1】:

    因为你的 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))
    }
    

    在cmets中也提到过,在没有'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 错误。

    【讨论】:

    • 如果 e 不在缓冲区中,这将导致无限循环。
    【解决方案2】:

    当您进入循环时,您只会读取一次缓冲区。所以v 的值总是'u'。您也可以通过读取 for 循环的 post 语句中的下一个字节来解决它:

    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 没有任何问题。实际上,在 Go 中将Read() 循环写为无条件的for 循环和循环中的break 在适当的时候是非常惯用的(通常当你收到一个io.EOF 错误,表明你已经读到了所有内容的结尾)。它导致代码更易于阅读,尤其是当有许多条件应该导致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的错误检查尤其重要,否则如果你的缓冲区中没有'e',你就会陷入死循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多