01
介绍
Golang 语言中内置了两种字符类型,分别是 byte 的字节类类型,和 rune 的字符类类型。其中 byte 是 uint8 的别名,表示 ASCII 码的一个字符,占用 1 个字节,rune 是 int32 的别名,表示 UTF-8 字符,占用 4 个字节。
[]byte
表示字节切片,因为字符串也可以表示为字节切片,所以 bytes 包的函数和 strings 包的函数比较相似。
本文主要讲解 bytes(byte slice)包的使用方法,并不会涉及比较 string 和 []byte
相关的内容,比如二者的底层实现、区别和相互转换等。
02
函数
bytes 包提供了很多操作字节切片的函数,大致分为如下几类:
- 比较
- 包含
- 索引
- 分割
- 转换
- 清除
限于篇幅,我们无法将所有函数都介绍,本文我们在每个分类中挑选比较常用的函数来介绍。
比较
- func Compare(a, b []byte) int Compare 函数用于按照字典序比较两个字节切片的大小,返回值有 3 种情况,分别是:
- 返回 0,代表 a == b
- 返回 -1,代表 a < b
- 返回 +1,代表 a > b
注意:nil 作为参数,表示一个空切片。
- func Equal(a, b []byte) bool Equal 函数用于比较两个字节切片的长度和字节是否都相等,返回值是一个 bool 类型。
注意:nil 作为函数,表示一个空切片。
包含
- func Contains(b, subslice []byte) bool Contains 函数用于判断 subslice 子字节切片是否包含在 b 字节切片,返回值是一个 bool 类型。
- func Count(s, sep []byte) int Count 函数用于统计 sep 字节切片在 s 字节切片中非重叠实例数。
注意:如果 sep 是一个空切片,返回值是 s 切片长度加 1。
- func HasPrefix(s, prefix []byte) bool HasPrefix 函数用于判断字节切片 s 是否以 prefix 开头,返回值是一个 bool 类型。
- func HasSuffix(s, suffix []byte) bool HasSuffix 函数用于判断字节切片 s 是否以 suffix 结尾,返回值是一个 bool 类型。
索引
- func Index(s, sep []byte) int Index 函数用于查找 sep 在 s 中第一次出现的索引下标,如果没有则返回 -1。
- func LastIndex(s, sep []byte) int LastIndex 函数用于查找 sep 在 s 中最后一次出现的索引下标,如果没有则返回 -1。
分割
- func Split(s, sep []byte) [][]byte Split 函数用于将 sep 作为分割符,将 s 分割,返回拆分之后的字节切片。
注意:如果 sep 为空,将按照每个字节进行拆分。
- func SplitN(s, sep []byte, n int) [][]byte SplitN 函数用于将 sep 作为分割符,将 s 分割 n 份,返回拆分之后的字节切片。
转换
- func ToLower(s []byte) []byte ToLower 函数用于将字节切片所有字节全部转换为小写字母,返回该字节切片的一个副本。
- func ToUpper(s []byte) []byte ToUpper 函数用于将字节切片所有字节全部转换为大小字母,返回该字节切片的一个副本。
清除
- func Trim(s []byte, cutset string) []byte Trim 函数返回清除 s 中开头和结尾存在的 cutset 之后的一个子切片。
- func TrimLeft(s []byte, cutset string) []byte TrimLeft 函数返回清除 s 中开头存在的 cutset 之后的一个子切片。
- func TrimRight(s []byte, cutset string) []byte TrimRight 函数返回清除 s 中结尾存在的 cutset 之后的一个子切片。
- func TrimSpace(s []byte) []byte TrimSpace 函数返回清除 s 中开头和结尾存在的
\t\n\r
之后的一个子切片。
03
Buffer
Buffer 定义了一个可读写和可变大小的字节缓冲区,源码如下:
type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] lastRead readOp // last read operation, so that Unread* can work correctly. }
阅读源码,我们发现 Buffer 结构中的字段 buf 是 []byte
类型,用于存储数据,字段 off 是 int 类型,用于记录读写位置。
创建 Buffer
创建 BUffer 有以下三种方式:
- var b bytes.Buffer
- func NewBuffer(buf []byte) *Buffer 使用 NewBuffer 函数
- func NewBufferString(s string) *Buffer 使用 NewBufferString 函数
注意:三种方式的区别是 2 和 3 相比 1,可以在创建 Buffer 的同时初始化数据,其中 2 和 3 的区别是创建 Buffer 时,用于初始化的数据类型不同。
Buffer 方法
Buffer 结构提供了很多方法,限于篇幅,本文也是只介绍一些比较常用的。
- func (b *Buffer) Len() int Len 方法用于获取缓冲区未读的字节数。
- func (b *Buffer) String() string String 方法用于将缓冲区未读数据作为字符串返回。
- func (b *Buffer) Truncate(n int) Truncate 方法用于截断缓冲区前 n 个未读字节之后所有字节。
- func (b *Buffer) Reset() Reset 方法用于将缓冲区置空。
- func (b *Buffer) Grow(n int) Grow 方法用于增加 n 字节的缓冲区的容量。
- func (b *Buffer) Read(p []byte) (n int, err error) Read 方法用于读取缓冲区 len(p) 的字节。
- func (b *Buffer) Next(n int) []byte Next 方法用于读取缓冲区下一个 n 字节的数据。
注意:Next 方法和 Read 方法的区别是,Next 是对当前缓冲区直接进行 slice 操作并返回结果,Read 是从当前缓冲区拷贝数据到新的 slice。
- func (b *Buffer) Write(p []byte) (n int, err error) Write 方法用于将 p 追加到当前缓冲区。
- func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) WriteTo 方法用于将缓冲区中的数据写入到一个 writer 中。
04
Reader
Reader 实现了 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScanner, io.RuneScanner
接口。可以读取 []byte
。与 Buffer 可读写不同,Reader 是只读和支持查找。下面是 Reader 结构的源码:
type Reader struct { s []byte i int64 // current reading index prevRune int // index of previous rune; or < 0 }
Reader 结构中的字段 s 是一个 []byte
类型,用于存储数据,字段 i 是一个 int64 类型,用于存储当前读取的索引位置。
创建 Reader
func NewReader(b []byte) *Reader
使用 NewReader 函数可以创建一个读取 b 的 Reader。
Reader 方法
Reader 也提供了很多方法,我们也将只介绍一些常用的方法。
- func (r *Reader) Len() int Len 方法返回未读字节数。
- func (r *Reader) Size() int64 Size 方法返回数据的总长度。
- func (r *Reader) Reset(b []byte) Reset 方法将数据重置为 b。
- func (r *Reader) Read(b []byte) (n int, err error) Read 方法实现了
io.Reader
接口。 - func (r *Reader) WriteTo(w io.Writer) (n int64, err error) WriteTo 方法实现了
io.WriterTo
接口。
05
总结
本文介绍了 Golang 语言标准库的 bytes 包的函数和两个结构,Buffer 和 Reader,以及它们各自的方法。通过阅读本文,读者可以了解 bytes 包的使用方法和部分底层实现。
bytes 包提供的函数不止文中介绍的这些,感兴趣的读者,建议阅读官方文档了解文中未被提及的函数。