2016-07-11 32 views
1

当前我正在编写一个从bytes.Buffer中读取缓冲区的程序。它应该在发现字符e时停止阅读。但是当我使用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表达式是一种非常难看且容易出错的方式来解决这个问题。

回答

4

因为你的for循环是空post statement(你只有初始化语句),这样你就不会在每次迭代读取下一个字节(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错误当缓冲区为空时。

+2

如果e不在缓冲区中,这将导致无限循环。 – OneOfOne

3

你只是读取缓冲一次,当你进入循环。所以v的值将始终为'u'。您可以通过在读取下一个字节for循环的后声明中还解决这个问题:

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。其实这是在走得很地道在适当的时候(通常,当你得到一个io.EOF错误,表示你达到无论你正在阅读的结尾)写从环Read()环路作为conditionless for循环和break。它会导致代码更容易阅读,特别是当有许多条件会导致break。编写代码的惯用和首选(IMHO)方法是:

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

相关问题