我在查看Go源码时发现,在
bufio.Reader.collectFragments
(ReadSlice
和ReadString
使用的助手)中,一个看似严肃的ErrBufferFull
被忽略了,具体来说:
func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
var frag []byte
// Use ReadSlice to look for delim, accumulating full buffers.
for {
var e error
frag, e = b.ReadSlice(delim)
if e == nil { // got final fragment
break
}
if e != ErrBufferFull { // unexpected error
^^^^^^^^^^^^^^^^^^^^^ This ensures that ErrBufferFull will not break the loop
err = e
break
}
// Make a copy of the buffer.
buf := bytes.Clone(frag)
fullBuffers = append(fullBuffers, buf)
totalLen += len(buf)
}
totalLen += len(frag)
return fullBuffers, frag, totalLen, err
}
(go/src/bufio/bufio.go,第446行,Go 1.22)
如果
ReadSlice
返回 ErrBufferNull
,则会被忽略。复制完整的缓冲区,并开始新的迭代,再次调用 ReadSlice
。
但是,当缓冲区已满时,
ReadSlice
“失败”,并且似乎没有任何逻辑来增长或清除已满的缓冲区。
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
s := 0 // search start index
for {
// Search buffer.
if i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i >= 0 {
i += s
line = b.buf[b.r : b.r+i+1]
b.r += i + 1
break
}
// Pending error?
if b.err != nil {
line = b.buf[b.r:b.w]
b.r = b.w
err = b.readErr()
break
}
// Buffer full?
if b.Buffered() >= len(b.buf) {
b.r = b.w
line = b.buf
err = ErrBufferFull
break
}
s = b.w - b.r // do not rescan area we scanned before
b.fill() // buffer is not full
}
// Handle last byte, if any.
if i := len(line) - 1; i >= 0 {
b.lastByte = int(line[i])
b.lastRuneSize = -1
}
return
}
(go/src/bufio/bufio.go,第347行,Go 1.22)
据我了解,这可能会导致
collectFragments
中的循环永远运行。然而,由于 ErrBufferFull
被 明确 忽略,我觉得这是设计使然,我错过了一些东西。
有人可以帮我理解吗?谢谢!
这在
ReadSlice
文档中进行了解释:
如果缓冲区在没有分隔符的情况下已满,ReadSlice 会失败并出现错误 ErrBufferFull。
您还应该注意到,如果返回 ErrBufferFull,则算法在将切片附加到另一个切片后继续读取,因此它会以块的形式读取。