上一篇:
Go源码学习:bytes包 - 1.2 - buffer.go -(1)
11、Len:返回缓冲区未读部分的字节数
// Len 返回缓冲区未读部分的字节数;
// b.Len() == len(b.Bytes())。
func (b *Buffer) Len() int { return len(b.buf) - b.off }
解释:
Len
方法是一个Buffer
结构体的方法,返回缓冲区中未读部分的字节数。- 等效于
len(b.Bytes())
,即未读部分的字节数。
作用:
Len
方法用于获取缓冲区中未读部分的字节数,帮助确定还有多少未读取的数据。
12、Cap:返回缓冲区底层字节切片的容量
// Cap 返回缓冲区底层字节切片的容量,即为缓冲区数据分配的总空间。
func (b *Buffer) Cap() int { return cap(b.buf) }
解释:
Cap
方法是一个Buffer
结构体的方法,返回缓冲区底层字节切片的容量,即为缓冲区数据分配的总空间。
作用:
Cap
方法用于获取缓冲区底层字节切片的容量,即缓冲区最多能容纳多少字节的数据。
13、Available:返回缓冲区中未使用的字节数
// Available 返回缓冲区中未使用的字节数。
func (b *Buffer) Available() int { return cap(b.buf) - len(b.buf) }
解释:
Available
方法是一个Buffer
结构体的方法,返回缓冲区中未使用的字节数,即缓冲区还有多少可用空间。
作用:
Available
方法用于获取缓冲区中未使用的字节数,帮助确定缓冲区还有多少可用空间用于写入数据。
14、Truncate:截断缓冲区保留前n个未读字节
// Truncate 保留缓冲区的前n个未读字节,丢弃其余部分,但继续使用相同的分配存储。
// 如果 n 为负数或大于缓冲区长度,则引发 panic。
func (b *Buffer) Truncate(n int) {
// 如果 n 为零,则重置缓冲区。
if n == 0 {
b.Reset()
return
}
// 重置上次读取的操作标记。
b.lastRead = opInvalid
// 如果 n 为负数或大于缓冲区长度,则引发 panic。
if n < 0 || n > b.Len() {
panic("bytes.Buffer: truncation out of range")
}
// 将缓冲区截断至前 n 个未读字节。
b.buf = b.buf[:b.off+n]
}
解释:
Truncate
方法是一个Buffer
结构体的方法,用于截断缓冲区保留前 n 个未读字节,丢弃其余部分。- 如果 n 为零,则调用
Reset
方法重置缓冲区。 - 重置了上次读取的操作标记。
- 如果 n 为负数或大于缓冲区长度,则引发 panic。
- 最终,将缓冲区截断至前 n 个未读字节。
作用:
Truncate
方法用于调整缓冲区的大小,保留前 n 个未读字节,丢弃其余部分。
15、Reset:重置缓冲区为初始状态
// Reset 重置缓冲区为初始状态,
// 但保留底层存储以供将来的写入使用。
// Reset 等同于 Buffer.Truncate(0)。
func (b *Buffer) Reset() {
// 将缓冲区切片长度设置为零,即清空缓冲区。
b.buf = b.buf[:0]
// 重置偏移量和上次读取的操作标记。
b.off = 0
b.lastRead = opInvalid
}
解释:
Reset
方法是一个Buffer
结构体的方法,用于重置缓冲区为初始状态,但保留底层存储以供将来的写入使用。- 将缓冲区切片长度设置为零,即清空缓冲区。
- 同时,重置偏移量和上次读取的操作标记。
作用:
Reset
方法用于将缓冲区重置为初始状态,清空已有数据,但保留底层存储以供后续写入使用。
16、tryGrowByReslice:尝试通过重新切片进行快速增长
// tryGrowByReslice 是 grow 的内联版本,用于内部缓冲区只需要重新切片的快速情况。
// 它返回应写入字节的索引以及是否成功。
func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
// 如果缓冲区的剩余容量足够,直接重新切片。
if l := len(b.buf); n <= cap(b.buf)-l {
b.buf = b.buf[:l+n]
return l, true
}
// 如果容量不足,返回失败标记。
return 0, false
}
解释:
tryGrowByReslice
方法是一个Buffer
结构体的方法,用于在内部缓冲区只需要重新切片的快速情况下进行增长。- 如果缓冲区的剩余容量足够,直接重新切片,返回应写入字节的索引以及成功标记。
- 如果容量不足,返回失败标记。
作用:
tryGrowByReslice
方法用于在缓冲区容量足够的情况下进行快速增长,通过重新切片内部缓冲区。
17、grow:增长缓冲区以保证足够空间
// grow 增长缓冲区以保证至少有 n 个额外字节的空间。
// 返回应写入字节的索引。
// 如果缓冲区无法增长,将引发 ErrTooLarge 错误。
func (b *Buffer) grow(n int) int {
m := b.Len()
// 如果缓冲区为空,重置以释放空间。
if m == 0 && b.off != 0 {
b.Reset()
}
// 尝试通过重新切片的方式进行增长。
if i, ok := b.tryGrowByReslice(n); ok {
return i
}
// 如果缓冲区为空且 n 小于等于 smallBufferSize,直接创建新的小缓冲区。
if b.buf == nil && n <= smallBufferSize {
b.buf = make([]byte, n, smallBufferSize)
return 0
}
c := cap(b.buf)
if n <= c/2-m {
// 可以通过滑动而不是分配新的切片来增长。
// 我们只需要 m+n <= c 来滑动,但我们让容量增长两倍,以免花费过多时间复制。
copy(b.buf, b.buf[b.off:])
} else if c > maxInt-c-n {
panic(ErrTooLarge)
} else {
// 添加 b.off 以考虑 b.buf[:b.off] 从前面切片掉的情况。
b.buf = growSlice(b.buf[b.off:], b.off+n)
}
// 恢复 b.off 和 len(b.buf)。
b.off = 0
b.buf = b.buf[:m+n]
return m
}
解释:
grow
方法是一个Buffer
结构体的方法,用于增长缓冲区以保证至少有 n 个额外字节的空间。- 获取当前缓冲区的长度
m
。 - 如果缓冲区为空且偏移量不为零,则调用
Reset
方法重置缓冲区,以释放空间。 - 尝试通过重新切片的方式进行增长,如果成功,返回写入字节的索引。
- 如果缓冲区为空且 n 小于等于
smallBufferSize
,直接创建新的小缓冲区。 - 获取当前缓冲区的容量
c
。 - 如果 n 小于等于
c/2-m
,则可以通过滑动而不是分配新的切片来增长,避免过多的复制。 - 如果缓冲区容量大于
maxInt-c-n
,引发ErrTooLarge
错误,防止溢出。 - 否则,通过调用
growSlice
方法增长缓冲区的切片。 - 最终,恢复偏移量和缓冲区的长度,并返回写入字节的索引。
作用:
grow
方法用于增长缓冲区以确保至少有 n 个额外字节的空间。- 它采用不同的策略,包括重新切片和创建新的缓冲区,以满足增长的需求。
18、Grow:增长缓冲区容量
// Grow 增长缓冲区的容量,以保证至少有另外 n 个字节的空间。
// 在调用 Grow(n) 后,可以写入至少 n 个字节到缓冲区而无需另外分配空间。
// 如果 n 为负数,Grow 将引发 panic。
// 如果缓冲区无法增长,将引发 [ErrTooLarge] 错误。
func (b *Buffer) Grow(n int) {
if n < 0 {
panic("bytes.Buffer.Grow: negative count")
}
m := b.grow(n)
b.buf = b.buf[:m]
}
解释:
Grow
方法是一个Buffer
结构体的方法,用于增长缓冲区的容量,以确保至少有另外 n 个字节的空间。- 如果 n 为负数,
Grow
将引发 panic。 - 调用内部的
grow
方法获取实际增长后的长度m
,然后截取缓冲区至该长度。
作用:
Grow
方法用于增长缓冲区的容量,确保至少有另外 n 个字节的空间。- 这样在之后的写入操作中,可以直接写入至少 n 个字节到缓冲区而无需另外分配空间。
19、Write:写入内容到缓冲区
// Write 将 p 的内容追加到缓冲区,根据需要增长缓冲区。
// 返回值 n 是 p 的长度;err 始终为 nil。如果缓冲区变得过大,Write 将引发 [ErrTooLarge] 错误。
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(p))
if !ok {
m = b.grow(len(p))
}
return copy(b.buf[m:], p), nil
}
解释:
Write
方法是一个Buffer
结构体的方法,用于将字节切片p
的内容追加到缓冲区中,并根据需要增长缓冲区的容量。- 在写入之前,将
lastRead
字段设置为opInvalid
,表示上一次读取的操作无效。 - 使用
tryGrowByReslice
方法尝试通过重新切片的方式增长缓冲区,如果成功返回ok
为 true。 - 如果不成功,则调用
grow
方法进行增长,获取实际增长后的长度m
。 - 使用
copy
将p
的内容复制到缓冲区中的相应位置,返回复制的字节数和 nil 错误。
作用:
Write
方法用于将字节切片p
的内容追加到缓冲区,确保缓冲区的容量足够。- 如果缓冲区变得过大,会引发 [ErrTooLarge] 错误,避免无限制地增长缓冲区。
20、WriteString:将字符串写入缓冲区
// WriteString 将字符串 s 的内容追加到缓冲区,根据需要增长缓冲区。
// 返回值 n 是 s 的长度;err 始终为 nil。如果缓冲区变得过大,WriteString 将引发 [ErrTooLarge] 错误。
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
return copy(b.buf[m:], s), nil
}
解释:
WriteString
方法是一个Buffer
结构体的方法,用于将字符串s
的内容追加到缓冲区中,并根据需要增长缓冲区的容量。- 在写入之前,将
lastRead
字段设置为opInvalid
,表示上一次读取的操作无效。 - 使用
tryGrowByReslice
方法尝试通过重新切片的方式增长缓冲区,如果成功返回ok
为 true。 - 如果不成功,则调用
grow
方法进行增长,获取实际增长后的长度m
。 - 使用
copy
将字符串s
的内容复制到缓冲区中的相应位置,返回复制的字节数和 nil 错误。
作用:
WriteString
方法用于将字符串s
的内容追加到缓冲区,确保缓冲区的容量足够。- 如果缓冲区变得过大,会引发 [ErrTooLarge] 错误,避免无限制地增长缓冲区。