字符串
💥本文章所有相关go代码参考自go 1.18+版本
- 使用反引号
(``)
或双引号("")
来定义字符串,反引号表示原生的字符串,即不进行转义。
双引号
- 字符串使用双引号括起来,其中相关的转义字符将被替换。
|
|
|
|
反引号
- 字符串使用反引号括起来,其中相关的转义字符不会被替换。
|
|
|
|
- 双引号和反引号存储的区别。
|
|
字符串
Go
语言中的string
类型是一种值类型,存储的字符串是不可变的。- 如果需要修改
string
的内容,需要将string
转换为[]byte
或[]rune
,并且修改后的string
内容是重新生成的。 Go
默认使用UTF-8
编码,对Unicode
的支持非常好。- 字符串存储结构:
|
|
|
|
byte 和 rune
- 这两个类型是处理字符相关。
type byte = uint8
、type rune = int32
。
|
|
Unicode 转 UTF-8
|
|
字符串比较
- 一般的比较运算符(
==
、!=
、<
、<=
、>=
、>
)通过在内存中接字节比较来实现字符串的对比。 - 比较源码函数:
|
|
字符串长度
len()
函数获取字符串所占的字节长度,由字符串的结构可知字符串的长度保存在字符串的第二个字段中。
|
|
- 内置的
len()
函数获取的是字节的长度和,而不是字符数量。
|
|
- 字符串的内容(纯字节)可以通过标准索引来获取,在中括号[]内写入索引,索引从0开始。
- 字符串
str
的第一个字节str[0]
。 - 第
i
字节str[i - 1]
。 - 最后1个字节
str[len(str) - 1]
。
- 字符串
|
|
- 如果字符串含有中文等字符,可以看到每个中文字符的索引值相差3。
Go
的range
循环在处理字符串的时候,会自动隐式解码UTF-8
字符串,关于循环的处理参看for
相关文档。
|
|
字符串拼接
- 将多个字符串拼接成一个字符串。
+
拼接
- 下面的示例,字符串都是不可变的,每次运算都会产生一个新的字符串,所以会产生很多临时的字符串。
- 不仅没用还会给垃圾回收带来额外负担,所以性能比较差。
- 数量较少的
+
还行,比如 5 个或以下。
|
|
fmt.Sprintf()
- 内部使用
[]byte
实现,不像直接使用+
拼接产生临时的字符串。 - 但是内部逻辑比较复杂,很多额外的判断,用到了接口,所以性能一般。
|
|
strings.Join()
Join
会先根据字符串数组的内容,计算一个拼接之后的长度。- 然后申请对应大小的内存,一个一个字符串填入。
- 在已有一个数组的情况下效率很高,但是构造一个本来没有的数据代价也不小。
|
|
bytes.Buffer
- 比较理想,可以当成可变字符使用,对内存的增长也有优化。
- 如果能预估字符串的长度,可以使用
buffer.Grow()
接口来设置capacity
,就是设置切片容量,避免翻倍扩容造成性能下降。
|
|
strings.Builder
- 内部通过切片来保存和管理内容。
- 切片内部则是通过一个指针指向实际保存内容的数组。
strings.Builder
同样也提供了Grow()
来支持预定于容量,就是设置切片容量,避免翻倍扩容造成性能下降。- 当可以预定义需要使用的容量时,
strings.Builder
就能避免因扩容产生新的切片。 strings.Builder
是非线程安全的,性能和bytes.Buffer
相差无几。
|
|
字符串处理
- 标准库四个对字符串处理包:
bytes
、strings
、strconv
、unicode
。
包 | 描述 |
---|---|
strings |
提供了许多如字符串的查询、替换、比较、截断、拆分和合并等功能 |
bytes |
该包也提供了类似strings 功能的函数,但是针对和字符串有着相同结构的[]byte 类型,因为字符串只是只读,因此逐步构建字符串会导致很多分配和复制。在这种情况下,使用bytes.Buffer 类型将更有效 |
strconv |
提供了布尔型、整型数、浮点数和对应字符串的相互转换,还提供了双引号转义相关的转换 |
unicode |
提供了IsDigit 、IsLetter 、IsUppe r和IsLower 等类似功能,用于给定字符分类 |
判断以某字符串开头或结尾
strings.HasPrefix(s, prefix string) bool
判断是否以某个字符串开头。strings.HasSuffix(s, suffix string) bool
判断是否以某个字符串结尾。
|
|
字符串分割
strings.Split(s, sep string) []string
使用sep
字符串分隔s
字符串。
|
|
返回子串索引
strings.Index(s, substr string) int
返回第一次匹配到的索引。strings.LastIndex(a, substr string) int
返回最后一个匹配到的索引。
|
|
字符串连接
strings.Join(a []string, sep string) string
使用sep
字符串拼接a
字符串切片。
|
|
字符串替换
strings.Replace(s, old, new string, n int) string
在s
字符串中搜索old
字符串并替换成new
字符串,n
替换个数。
|
|
统计字符在字符串中的次数
strings.Count(s, substr string) int
统计substr
字符串在s
字符串中出现的次数。
|
|
判断字符串的包含关系
strings.Contains(s, substr string) bool
判断s
字符串是否包含substr
字符串。
|
|
字符串转义符
- Go 语言的字符串常见转义符包含回车、换行、单双引号、制表符等,如下表所示。
转义 | 含义 |
---|---|
\r |
回车符(返回行首) |
\n |
换行符(直接跳到下一行的同列位置) |
\t |
制表符 |
\' |
单引号 |
\" |
双引号 |
\ |
反斜杠 |
|
|
byte和rune类型
- 组成每个字符串的元素叫做字符。
- 可以通过遍历或者单个获取字符串元素获得字符。
- 字符用英文单引号(
'
)包裹起来。
|
|
Go
语言的字符有以下两种:uint8
类型,或者叫byte
型,代表了ASCII
码的一个字符。rune
类型,代表一个Unicode
字符。
- 当需要处理中文、日文或者其他复合字符时,则需要用到
rune
类型。rune
类型实际是一个int32
。Go
使用了特殊的rune
类型来处理Unicode
,让基于Unicode
的文本处理更为方便。
- 也可以使用
byte
型进行默认字符串处理。
|
|
修改字符串
- 要修改字符串,需要先将其转换成
[]rune
或[]byte
,完成后再转换为string
。 - 无论哪种转换,都会重新分配内存。
|
|
|
|
类型转换
Go
语言中只有显示类型转换,没有隐式类型转换,该语法只能在两个类型之间支持相互转换的时候使用。- 强制类型转换的基本语法如下:
T(表达式)
:注意区分函数调用情况。因为函数调用与显示转换类型形式相似。T
表示要转换的类型。
- 如计算直角三角形的斜边长时使用math包的Sqrt()函数。
- 该函数接收的是
float64
类型的参数,而变量a和b都是int类型的,这个时候就需要将a和b强制类型转换为float64
类型。
- 该函数接收的是
|
|
总结
- 字符串被设计成只读数据,这样在多线程时操作字符串时不需要加锁避免并发。