Go 语言标准库 —— bytes 包(字节切片操作)
🔹 概述
bytes 包提供了用于操作字节切片([]byte)的函数,类似于 strings 包对字符串的操作。
主要功能:
- 字节切片比较、查找、分割
- 字节切片与字符串转换
- Buffer 缓冲区操作
- Reader 读取器
🔹 Buffer 类型
字节缓冲区
bytes.Buffer struct
-
说明:
- 实现了 io.Reader、io.Writer、io.ByteReader、io.ByteWriter 等接口
- 内部维护一个可增长的字节缓冲区
- 适合用于高效地构建或处理字节数据
-
字段:
- 内部自动管理,无需手动操作
-
常用方法详解
-
Write 方法
- 说明:写入字节切片
- 方法:
Write(p []byte) (n int, err error) - 注意:缓冲区会自动扩展
- 示例:
var buf bytes.Buffer buf.Write([]byte("hello"))
-
WriteString 方法
- 说明:写入字符串
- 方法:
WriteString(s string) (n int, err error) - 注意:避免字符串到 []byte 的转换
- 示例:
var buf bytes.Buffer buf.WriteString("hello")
-
WriteByte 方法
- 说明:写入单个字节
- 方法:
WriteByte(c byte) error - 注意:最高效的写入方式
- 示例:
var buf bytes.Buffer buf.WriteByte('A')
-
WriteRune 方法
- 说明:写入单个 rune(Unicode 字符)
- 方法:
WriteRune(r rune) (n int, err error) - 注意:自动进行 UTF-8 编码
- 示例:
var buf bytes.Buffer buf.WriteRune('中')
-
Read 方法
- 说明:从缓冲区读取数据
- 方法:
Read(p []byte) (n int, err error) - 注意:读取后数据会从缓冲区移除
- 示例:
buf := bytes.NewBuffer([]byte("hello")) data := make([]byte, 5) buf.Read(data)
-
ReadByte 方法
- 说明:读取并返回下一个字节
- 方法:
ReadByte() (byte, error) - 示例:
b, _ := buf.ReadByte()
-
Bytes 方法
- 说明:返回缓冲区内容的字节切片
- 方法:
Bytes() []byte - 注意:返回的切片在下一次写操作后会失效
- 示例:
data := buf.Bytes()
-
String 方法
- 说明:返回缓冲区内容的字符串
- 方法:
String() string - 注意:不会复制底层数据(高效)
- 示例:
result := buf.String()
-
Len 方法
- 说明:返回缓冲区中可读的字节数
- 方法:
Len() int - 示例:
length := buf.Len()
-
Cap 方法
- 说明:返回缓冲区的容量
- 方法:
Cap() int - 示例:
capacity := buf.Cap()
-
Reset 方法
- 说明:清空缓冲区,复用缓冲区
- 方法:
Reset() - 注意:不会释放内存,可重复使用
- 示例:
buf.Reset() // 清空
-
Truncate 方法
- 说明:截断缓冲区,保留前 n 个字节
- 方法:
Truncate(n int) - 注意:n 必须 >= 0
- 示例:
buf.Truncate(5) // 保留前 5 字节
-
Grow 方法
- 说明:预分配容量
- 方法:
Grow(n int) - 注意:知道最终大小时使用,减少内存分配
- 示例:
buf.Grow(1024) // 预分配 1024 字节
-
UnreadByte 方法
- 说明:回退一个字节
- 方法:
UnreadByte() error - 注意:只能回退最近读取的一个字节
- 示例:
buf.UnreadByte()
-
-
示例(完整)
package main import ( "fmt" "bytes" ) func main() { var buf bytes.Buffer // 预分配容量 buf.Grow(100) // 写入数据 buf.WriteString("hello ") buf.WriteByte('G') buf.WriteString("o") buf.WriteRune('!') // 查看内容 fmt.Println("内容:", buf.String()) fmt.Println("长度:", buf.Len()) fmt.Println("容量:", buf.Cap()) // 读取 data := buf.Bytes() fmt.Println("字节:", data) // 清空并复用 buf.Reset() buf.WriteString("world") fmt.Println("重置后:", buf.String()) } -
使用场景示例
-
高效构建字符串
- 示例:
var buf bytes.Buffer for i := 0; i < 1000; i++ { buf.WriteString(fmt.Sprintf("%d,", i)) } result := buf.String()
- 示例:
-
作为 io.Writer 使用
- 示例:
var buf bytes.Buffer io.Copy(&buf, file) data := buf.Bytes()
- 示例:
-
作为 io.Reader 使用
- 示例:
buf := bytes.NewBuffer([]byte("data")) io.Copy(os.Stdout, buf)
- 示例:
-
临时数据存储
- 示例:
var buf bytes.Buffer buf.Write(header) buf.Write(body) send(buf.Bytes())
- 示例:
-
🔹 Reader 类型
字节读取器
bytes.Reader struct
-
说明:
- 实现了 io.Reader、io.Seeker、io.ReaderAt 等接口
- 从字节切片读取数据,支持随机访问
- 类似 strings.Reader,但操作的是 []byte
-
常用方法详解
-
Read 方法
- 说明:从读取器读取数据
- 方法:
Read(p []byte) (n int, err error) - 注意:读取后内部偏移量会移动
- 示例:
r := bytes.NewReader([]byte("hello")) data := make([]byte, 5) r.Read(data)
-
ReadAt 方法
- 说明:从指定位置读取
- 方法:
ReadAt(p []byte, off int64) (n int, err error) - 注意:不影响内部偏移量
- 示例:
r := bytes.NewReader([]byte("hello")) data := make([]byte, 3) r.ReadAt(data, 2) // 从位置 2 读取
-
Seek 方法
- 说明:移动读取位置
- 方法:
Seek(offset int64, whence int) (int64, error) - 注意:whence=0 从头,1 从当前位置,2 从末尾
- 示例:
r := bytes.NewReader([]byte("hello")) r.Seek(2, 0) // 移动到位置 2
-
Len 方法
- 说明:返回未读取的字节数
- 方法:
Len() int - 示例:
remaining := r.Len()
-
Size 方法
- 说明:返回总字节数
- 方法:
Size() int64 - 示例:
total := r.Size()
-
Reset 方法
- 说明:重置为读取新的字节切片
- 方法:
Reset(b []byte) - 注意:复用 Reader
- 示例:
r.Reset([]byte("new data"))
-
-
示例(完整)
package main import ( "fmt" "bytes" "io" ) func main() { data := []byte("hello world") r := bytes.NewReader(data) // 读取全部 all, _ := io.ReadAll(r) fmt.Println("全部:", string(all)) // 重置并随机访问 r.Reset(data) r.Seek(6, 0) // 移动到 "world" buf := make([]byte, 5) r.Read(buf) fmt.Println("读取:", string(buf)) // ReadAt(不影响偏移量) buf2 := make([]byte, 5) r.ReadAt(buf2, 0) // 从头读取 fmt.Println("ReadAt:", string(buf2)) } -
使用场景示例
-
模拟 io.Reader
- 示例:
data := []byte("test data") r := bytes.NewReader(data) io.Copy(os.Stdout, r)
- 示例:
-
测试代码
- 示例:
func TestRead(t *testing.T) { r := bytes.NewReader([]byte("test")) // 测试读取逻辑 }
- 示例:
-
内存中的随机访问
- 示例:
r := bytes.NewReader(fileData) r.Seek(100, 0) // 跳到位置 100 r.Read(buf) // 读取数据
- 示例:
-
🔹 比较函数
字节切片比较
bytes.Equal(a, b []byte) bool
- 说明:
- 比较两个字节切片是否相等
- 长度和内容都必须相同
- 返回值:
- true 👉 相等
- false 👉 不相等
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.Equal([]byte("hello"), []byte("hello"))) // true fmt.Println(bytes.Equal([]byte("hello"), []byte("world"))) // false fmt.Println(bytes.Equal([]byte{}, []byte(nil))) // true(空和 nil 相等) }
带前缀比较
bytes.EqualFold(s, t []byte) bool
- 说明:
- 忽略大小写比较两个字节切片
- 支持 ASCII 字符
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.EqualFold([]byte("Hello"), []byte("hello"))) // true fmt.Println(bytes.EqualFold([]byte("Go"), []byte("GO"))) // true fmt.Println(bytes.EqualFold([]byte("test"), []byte("best"))) // false }
比较两个字节切片
bytes.Compare(a, b []byte) int
- 说明:
- 按字典序比较两个字节切片
- 基于字节值的比较
- 返回值:
- 0 👉 a == b
- -1 👉 a < b
- 1 👉 a > b
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.Compare([]byte("a"), []byte("b"))) // -1 fmt.Println(bytes.Compare([]byte("a"), []byte("a"))) // 0 fmt.Println(bytes.Compare([]byte("b"), []byte("a"))) // 1 }
🔹 查找函数
包含子切片
bytes.Contains(b, subslice []byte) bool
- 说明:
- 检查字节切片 b 是否包含子切片 subslice
- 返回值:
- true 👉 包含
- false 👉 不包含
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.Contains([]byte("hello world"), []byte("world"))) // true fmt.Println(bytes.Contains([]byte("hello"), []byte("x"))) // false }
包含任意字节
bytes.ContainsAny(b []byte, chars string) bool
- 说明:
- 检查字节切片 b 是否包含 chars 中的任意字节
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.ContainsAny([]byte("hello"), "aei")) // true fmt.Println(bytes.ContainsAny([]byte("hello"), "xyz")) // false }
包含指定字节
bytes.ContainsRune(b []byte, r rune) bool
- 说明:
- 检查字节切片 b 是否包含指定 rune
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.ContainsRune([]byte("hello"), 'e')) // true fmt.Println(bytes.ContainsRune([]byte("hello"), 'x')) // false }
统计出现次数
bytes.Count(s, sep []byte) int
- 说明:
- 统计子切片 sep 在 s 中出现的次数
- 非重叠计数
- 特殊情况:
- sep 为空时返回 len(s) + 1
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.Count([]byte("banana"), []byte("na"))) // 2 fmt.Println(bytes.Count([]byte("aaaa"), []byte("aa"))) // 2 fmt.Println(bytes.Count([]byte("hello"), []byte("x"))) // 0 }
查找子切片位置
bytes.Index(b, subslice []byte) int
- 说明:
- 返回子切片第一次出现的位置
- 未找到返回 -1
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.Index([]byte("hello world"), []byte("world"))) // 6 fmt.Println(bytes.Index([]byte("hello"), []byte("x"))) // -1 }
查找任意字节位置
bytes.IndexAny(b []byte, chars string) int
- 说明:
- 返回 chars 中任意字节第一次出现的位置
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.IndexAny([]byte("hello"), "aei")) // 1(e 的位置) fmt.Println(bytes.IndexAny([]byte("hello"), "xyz")) // -1 }
查找指定字节位置
bytes.IndexByte(b []byte, c byte) int
- 说明:
- 返回指定字节第一次出现的位置
- 比 Index 更高效(针对单字节)
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.IndexByte([]byte("hello"), 'e')) // 1 fmt.Println(bytes.IndexByte([]byte("hello"), 'x')) // -1 }
最后一个子切片位置
bytes.LastIndex(b, subslice []byte) int
- 说明:
- 返回子切片最后一次出现的位置
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.LastIndex([]byte("banana"), []byte("na"))) // 4 fmt.Println(bytes.LastIndex([]byte("hello"), []byte("l"))) // 3 }
🔹 分割函数
按子切片分割
bytes.Split(s, sep []byte) [][]byte
- 说明:
- 使用 sep 分割字节切片 s
- 返回分割后的切片数组
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { parts := bytes.Split([]byte("a,b,c"), []byte(",")) for i, p := range parts { fmt.Printf("%d: %s\n", i, string(p)) } // 0: a // 1: b // 2: c }
分割 N 次
bytes.SplitN(s, sep []byte, n int) [][]byte
- 说明:
- 最多分割 n-1 次,返回 n 个部分
- n < 0 表示不限制次数
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { // 分割 2 次,返回 3 部分 parts := bytes.SplitN([]byte("a,b,c,d"), []byte(","), 3) fmt.Printf("分割 2 次:%v\n", parts) // [a b c,d] // 不限制 parts2 := bytes.SplitN([]byte("a,b,c"), []byte(","), -1) fmt.Printf("不限制:%v\n", parts2) // [a b c] }
分割成多行
bytes.SplitAfter(s, sep []byte) [][]byte
- 说明:
- 类似 Split,但保留分隔符
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { parts := bytes.SplitAfter([]byte("a;b;c;"), []byte(";")) for i, p := range parts { fmt.Printf("%d: %s\n", i, string(p)) } // 0: a; // 1: b; // 2: c; }
分割 N 次并保留分隔符
bytes.SplitAfterN(s, sep []byte, n int) [][]byte
- 说明:
- SplitAfter 的 N 次版本
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { parts := bytes.SplitAfterN([]byte("a,b,c,d"), []byte(","), 2) fmt.Printf("%v\n", parts) // [a, b,c,d] }
🔹 修剪函数
修剪空白字符
bytes.TrimSpace(s []byte) []byte
- 说明:
- 移除首尾的空白字符(空格、制表符、换行等)
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte(" \t\nhello world \t\n") trimmed := bytes.TrimSpace(s) fmt.Printf("修剪后:%s\n", string(trimmed)) // hello world }
修剪指定字节
bytes.Trim(s []byte, cutset string) []byte
- 说明:
- 移除首尾在 cutset 中的任意字符
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("###hello###") trimmed := bytes.Trim(s, "#") fmt.Printf("修剪后:%s\n", string(trimmed)) // hello }
修剪前缀
bytes.TrimPrefix(s, prefix []byte) []byte
- 说明:
- 如果 s 以 prefix 开头,则移除 prefix
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("http://example.com") trimmed := bytes.TrimPrefix(s, []byte("http://")) fmt.Printf("修剪后:%s\n", string(trimmed)) // example.com }
修剪后缀
bytes.TrimSuffix(s, suffix []byte) []byte
- 说明:
- 如果 s 以后缀 suffix 结尾,则移除 suffix
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("file.txt") trimmed := bytes.TrimSuffix(s, []byte(".txt")) fmt.Printf("修剪后:%s\n", string(trimmed)) // file }
修剪左侧字符
bytes.TrimLeft(s []byte, cutset string) []byte
- 说明:
- 只移除左侧(开头)在 cutset 中的字符
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("###hello###") trimmed := bytes.TrimLeft(s, "#") fmt.Printf("修剪后:%s\n", string(trimmed)) // hello### }
修剪右侧字符
bytes.TrimRight(s []byte, cutset string) []byte
- 说明:
- 只移除右侧(结尾)在 cutset 中的字符
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("###hello###") trimmed := bytes.TrimRight(s, "#") fmt.Printf("修剪后:%s\n", string(trimmed)) // ###hello }
修剪左侧函数
bytes.TrimLeftFunc(s []byte, f func(rune) bool) []byte
- 说明:
- 使用条件函数判断是否移除左侧字符
- 示例(完整)
package main import ( "fmt" "bytes" "unicode" ) func main() { s := []byte(" \thello") trimmed := bytes.TrimLeftFunc(s, unicode.IsSpace) fmt.Printf("修剪后:%s\n", string(trimmed)) // hello }
修剪右侧函数
bytes.TrimRightFunc(s []byte, f func(rune) bool) []byte
- 说明:
- 使用条件函数判断是否移除右侧字符
- 示例(完整)
package main import ( "fmt" "bytes" "unicode" ) func main() { s := []byte("hello \t") trimmed := bytes.TrimRightFunc(s, unicode.IsSpace) fmt.Printf("修剪后:%s\n", string(trimmed)) // hello }
修剪两侧函数
bytes.TrimFunc(s []byte, f func(rune) bool) []byte
- 说明:
- 使用条件函数判断是否移除两侧字符
- 示例(完整)
package main import ( "fmt" "bytes" "unicode" ) func main() { s := []byte(" hello ") trimmed := bytes.TrimFunc(s, unicode.IsSpace) fmt.Printf("修剪后:%s\n", string(trimmed)) // hello }
🔹 替换函数
替换子切片
bytes.Replace(s, old, new []byte, n int) []byte
- 说明:
- 替换 s 中的 old 为 new
- n < 0 表示替换所有,n >= 0 表示最多替换 n 次
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { // 替换所有 s := bytes.Replace([]byte("hello world"), []byte("world"), []byte("Go"), -1) fmt.Printf("替换所有:%s\n", string(s)) // hello Go // 替换 1 次 s2 := bytes.Replace([]byte("aa bb aa"), []byte("aa"), []byte("cc"), 1) fmt.Printf("替换 1 次:%s\n", string(s2)) // cc bb aa }
替换所有子切片
bytes.ReplaceAll(s, old, new []byte) []byte
- 说明:
- 替换所有出现的 old 为 new
- Go 1.12+ 新增
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := bytes.ReplaceAll([]byte("aa bb aa"), []byte("aa"), []byte("cc")) fmt.Printf("替换所有:%s\n", string(s)) // cc bb cc }
重复字节切片
bytes.Repeat(b []byte, count int) []byte
- 说明:
- 返回 b 重复 count 次后的新切片
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := bytes.Repeat([]byte("ab"), 3) fmt.Printf("重复 3 次:%s\n", string(s)) // ababab }
🔹 大小写转换
转小写
bytes.ToLower(s []byte) []byte
- 说明:
- 将所有 ASCII 大写字母转换为小写
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := bytes.ToLower([]byte("HELLO World")) fmt.Printf("小写:%s\n", string(s)) // hello world }
转大写
bytes.ToUpper(s []byte) []byte
- 说明:
- 将所有 ASCII 小写字母转换为大写
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := bytes.ToUpper([]byte("hello World")) fmt.Printf("大写:%s\n", string(s)) // HELLO WORLD }
首字母大写
bytes.ToTitle(s []byte) []byte
- 说明:
- 将所有字母转换为标题格式(大写)
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := bytes.ToTitle([]byte("hello")) fmt.Printf("标题格式:%s\n", string(s)) // HELLO }
判断是否小写
bytes.IsLower(s []byte) bool
- 说明:
- 检查是否所有字母都是小写
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.IsLower([]byte("hello"))) // true fmt.Println(bytes.IsLower([]byte("Hello"))) // false }
判断是否大写
bytes.IsUpper(s []byte) bool
- 说明:
- 检查是否所有字母都是大写
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.IsUpper([]byte("HELLO"))) // true fmt.Println(bytes.IsUpper([]byte("Hello"))) // false }
判断是否标题格式
bytes.IsTitle(s []byte) bool
- 说明:
- 检查是否是标题格式(每个单词首字母大写)
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { fmt.Println(bytes.IsTitle([]byte("Hello"))) // true fmt.Println(bytes.IsTitle([]byte("hello"))) // false }
🔹 其他函数
转义
bytes.Clone(s []byte) []byte
- 说明:
- 返回字节切片的独立副本
- Go 1.20+ 新增
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { s := []byte("hello") clone := bytes.Clone(s) // 修改原切片不影响副本 s[0] = 'H' fmt.Printf("原切片:%s\n", string(s)) // Hello fmt.Printf("副本:%s\n", string(clone)) // hello }
标题化
bytes.ToValidUTF8(s, replacement []byte) []byte
- 说明:
- 将 s 转换为有效的 UTF-8
- 无效的 UTF-8 序列会被 replacement 替换
- Go 1.20+ 新增
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { // 包含无效 UTF-8 s := []byte("hello\x80\x81world") valid := bytes.ToValidUTF8(s, []byte("?")) fmt.Printf("有效 UTF-8: %s\n", string(valid)) // hello?world }
🔹 辅助函数
创建缓冲区
bytes.NewBuffer(b []byte) *bytes.Buffer
- 说明:
- 使用 b 初始化一个新的 Buffer
- b 的所有权转移给 Buffer
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { buf := bytes.NewBuffer([]byte("hello")) buf.WriteString(" world") fmt.Println(buf.String()) // hello world }
创建字符串缓冲区
bytes.NewBufferString(s string) *bytes.Buffer
- 说明:
- 使用字符串 s 初始化一个新的 Buffer
- 避免字符串到 []byte 的转换
- 示例(完整)
package main import ( "fmt" "bytes" ) func main() { buf := bytes.NewBufferString("hello") buf.WriteString(" world") fmt.Println(buf.String()) // hello world }
读取所有
bytes.ReadAll(r io.Reader) ([]byte, error)
- 说明:
- 从 r 读取所有数据到字节切片
- 类似 io.ReadAll
- 示例(完整)
package main import ( "fmt" "bytes" "strings" ) func main() { r := strings.NewReader("hello world") data, _ := bytes.ReadAll(r) fmt.Printf("读取:%s\n", string(data)) // hello world }
🔥 总结
核心类型
- bytes.Buffer 👉 可增长的字节缓冲区(实现了 io.Reader/Writer)
- bytes.Reader 👉 从字节切片读取(支持随机访问)
常用函数
比较:
bytes.Equal()👉 比较是否相等bytes.EqualFold()👉 忽略大小写比较bytes.Compare()👉 字典序比较
查找:
bytes.Contains()👉 包含子切片bytes.Index()👉 查找位置bytes.LastIndex()👉 最后出现位置bytes.Count()👉 统计次数
分割:
bytes.Split()👉 分割切片bytes.SplitN()👉 分割 N 次bytes.SplitAfter()👉 保留分隔符
修剪:
bytes.TrimSpace()👉 修剪空白bytes.TrimPrefix()👉 修剪前缀bytes.TrimSuffix()👉 修剪后缀
替换:
bytes.Replace()👉 替换子切片bytes.ReplaceAll()👉 替换所有bytes.Repeat()👉 重复切片
大小写:
bytes.ToLower()👉 转小写bytes.ToUpper()👉 转大写bytes.ToTitle()👉 标题格式
使用场景
- Buffer 👉 高效构建字节数据、作为 io.Reader/Writer
- Reader 👉 从内存读取数据、测试代码
- 查找函数 👉 日志分析、协议解析
- 分割函数 👉 解析 CSV、配置文件
- 修剪函数 👉 清理输入、格式化输出
- 替换函数 👉 模板处理、文本转换
与 strings 包的区别
- bytes 👉 操作
[]byte,适合二进制数据、网络传输 - strings 👉 操作
string,适合文本处理 - 性能 👉 bytes 避免了 string 和 []byte 之间的转换
- 接口 👉 bytes.Buffer 实现了更多 io 接口
最佳实践
- 使用 Buffer.Grow() 预分配容量
- 使用 bytes.Reader 代替 strings.Reader 处理二进制数据
- 使用 bytes.Equal() 而不是比较两个切片的内容
- 使用 bytes.TrimSpace() 清理用户输入
- 使用 bytes.ReplaceAll() 进行全局替换