strings / bytes / strconv
问题
Go 中字符串操作有哪些常用函数?strings 和 bytes 包有什么区别?
答案
strings 包
import "strings"
strings.Contains("hello world", "world") // true
strings.HasPrefix("hello", "he") // true
strings.HasSuffix("hello", "lo") // true
strings.Index("hello", "ll") // 2
strings.Count("hello", "l") // 2
strings.Replace("hello", "l", "L", -1) // "heLLo"(-1=全部替换)
strings.ToUpper("hello") // "HELLO"
strings.ToLower("HELLO") // "hello"
strings.TrimSpace(" hello ") // "hello"
strings.Trim("##hello##", "#") // "hello"
strings.Split("a,b,c", ",") // ["a", "b", "c"]
strings.Join([]string{"a", "b"}, ",") // "a,b"
strings.Repeat("ha", 3) // "hahaha"
strings.EqualFold("Go", "go") // true(忽略大小写)
// strings.Builder:高性能字符串拼接
var b strings.Builder
b.WriteString("hello")
b.WriteString(" world")
s := b.String() // "hello world"
// strings.NewReader:从字符串创建 io.Reader
r := strings.NewReader("hello")
bytes 包
bytes 包与 strings 类似,但操作 []byte:
import "bytes"
bytes.Contains([]byte("hello"), []byte("ell")) // true
bytes.Equal(a, b) // 比较
bytes.Join([][]byte{a, b}, []byte(",")) // 拼接
// bytes.Buffer:可读可写的缓冲区
var buf bytes.Buffer
buf.WriteString("hello")
buf.Write([]byte(" world"))
data := buf.Bytes() // []byte
str := buf.String() // string
strconv 包
import "strconv"
// int <-> string
strconv.Itoa(42) // "42"
strconv.Atoi("42") // 42, nil
// 更灵活的转换
strconv.FormatInt(255, 16) // "ff"(十六进制)
strconv.ParseInt("ff", 16, 64) // 255
// float <-> string
strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
strconv.ParseFloat("3.14", 64) // 3.14
// bool <-> string
strconv.FormatBool(true) // "true"
strconv.ParseBool("true") // true
strings.Builder vs bytes.Buffer vs +
| 方式 | 性能 | 特点 |
|---|---|---|
+ 拼接 | 最慢 | 每次创建新字符串 |
fmt.Sprintf | 较慢 | 方便但有反射开销 |
bytes.Buffer | 快 | 可读可写,更通用 |
strings.Builder | 最快 | 专为字符串拼接优化 |
常见面试问题
Q1: strings.Builder 为什么比 + 快?
答案:+ 每次拼接都分配新字符串并复制,。strings.Builder 内部维护一个 []byte,按需扩容,最后一次性转换为 string(通过 unsafe 零拷贝)。
Q2: strconv.Atoi 和 fmt.Sscanf 哪个好?
答案:strconv.Atoi 更好——无反射开销、无内存分配,性能约是 fmt.Sscanf 的 10 倍。