Go语言核心36讲(Go语言实战与应用十七)--学习笔记

本文深入探讨了Go语言中的bytes.Buffer,包括其扩容策略、内容泄露的可能性以及Bytes和Next方法的潜在问题。文章指出,Buffer值的扩容尽量减少内存分配和拷贝,而Bytes和Next方法的返回值可能导致内容泄露,建议在使用时注意数据安全。
摘要由CSDN通过智能技术生成

39 | bytes包与字节串操作(下)

在上一篇文章中,我们分享了bytes.Buffer中已读计数的大致功用,并围绕着这个问题做了解析,下面我们来进行相关的知识扩展。

知识扩展

问题 1:bytes.Buffer的扩容策略是怎样的?

Buffer值既可以被手动扩容,也可以进行自动扩容。并且,这两种扩容方式的策略是基本一致的。所以,除非我们完全确定后续内容所需的字节数,否则让Buffer值自动去扩容就好了。

在扩容的时候,Buffer值中相应的代码(以下简称扩容代码)会先判断内容容器的剩余容量,是否可以满足调用方的要求,或者是否足够容纳新的内容。

如果可以,那么扩容代码会在当前的内容容器之上,进行长度扩充。

更具体地说,如果内容容器的容量与其长度的差,大于或等于另需的字节数,那么扩容代码就会通过切片操作对原有的内容容器的长度进行扩充,就像下面这样:

b.buf = b.buf[:length+need]

反之,如果内容容器的剩余容量不够了,那么扩容代码可能就会用新的内容容器去替代原有的内容容器,从而实现扩容。

不过,这里还有一步优化。

如果当前内容容器的容量的一半,仍然大于或等于其现有长度(即未读字节数)再加上另需的字节数的和,即:

cap(b.buf)/2 >= b.Len() + need

那么,扩容代码就会复用现有的内容容器,并把容器中的未读内容拷贝到它的头部位置。

这也意味着其中的已读内容,将会全部被未读内容和之后的新内容覆盖掉。

这样的复用预计可以至少节省掉一次后续的扩容所带来的内存分配,以及若干字节的拷贝。

若这一步优化未能达成,也就是说,当前内容容器的容量小于新长度的二倍。

那么,扩容代码就只能再创建一个新的内容容器,并把原有容器中的未读内容拷贝进去,最后再用新的容器替换掉原有的容器。这个新容器的容量将会等于原有容量的二倍再加上另需字节数的和。

新容器的容量 =2* 原有容量 + 所需字节数

通过上面这些步骤,对内容容器的扩充基本上就完成了。不过,为了内部数据的一致性,以及避免原有的已读内容可能造成的数据混乱,扩容代码还会把已读计数置为0,并再对内容容器做一下切片操作,以掩盖掉原有的已读内容。

顺便说一下,对于处在零值状态的Buffer值来说,如果第一次扩容时的另需字节数不大于64,那么该值就会基于一个预先定义好的、长度为64的字节数组来创建内容容器。

在这种情况下,这个内容容器的容量就是64。这样做的目的是为了让Buffer值在刚被真正使用的时候就可以快速地做好准备。

package main

import (
	"bytes"
	"fmt"
)

func main() {
	// 示例1。
	var contents string
	buffer1 := bytes.NewBufferString(contents)
	fmt.Printf("The length of new buffer with contents %q: %d\n",
		contents, buffer1.Len())
	fmt.Printf("The capacity of new buffer with contents %q: %d\n",
		contents, buffer1.Cap())
	fmt.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值