本文你收货golang中字符串底层结构。了解字符串主要特点,并学习实战如何熟练使用string。
在 go 语言中,字符串实是一个不可改变的字节序列,其数据结构定义如下:
// 定义在 runtime/string.go 文件内
type stringStruct struct {
str unsafe.Pointer
len int
}
底层结构其实是一个结构体,所以字符串的赋值操作,也就是结构的复制过程,并不包含指针指向的内容的复制。下图是字符串hello存储结构示意图:
代码示例
package main
import "fmt"
func main() {
// 定义
s := "hello "
var a string // 空字符串
b := string("world")
fmt.Println(s)
fmt.Println(a)
fmt.Println(b)
}
程序输出
"hello"
"world"
这里需要注意的是,字符串并不支持cap(),会编译报错,原因是底层结构只有Len字段表示其长度。
代码示例
import "fmt"
func main() {
s1 := "hello"
s2 := "world"
// 判断是否相等
fmt.Println(s1 == s2)
// 判断是否不等
fmt.Println(s1 != s2)
// 获取长度
fmt.Println(len(s1))
// 字符串没有容量的概念记住!
// 下面这行会编译报错: s1 (variable of type string) for cap
// fmt.Println(cap(s1))
}
代码输出
false
true
5
代码示例
例子1:遍历普通字符串,输出字符与ascii数值
package main
import "fmt"
func main() {
s := "hello"
// 遍历输出ASCII值
for i, c := range s {
fmt.Printf("%d-%d-%c \n", i, c, c)
}
}
代码输出
0-104-h
1-101-e
2-108-l
3-108-l
4-111-o
例子2:有汉字情况下输出的是utf8值,注意观察第一列的下标变化
package main
import "fmt"
func main() {
// 如果有汉字
s := "你好, world"
for i, c := range s {
fmt.Printf("%d-%d-%c \n", i, c, c)
}
}
输出
0-20320-你
3-22909-好
6-44-,
7-32-
8-119-w
9-111-o
10-114-r
11-108-l
12-100-d
例子3:看一下直接用下标遍历会出现什么情况?
package main
import "fmt"
func main() {
// 如果有汉字
s := "你好, world"
for i := 0; i < len(s); i++ {
fmt.Printf("%d-%d-%c \n", i, s[i], s[i])
}
}
输出:竟然乱码了,猜一下为什么?
0-228-ä
1-189-½
2-160-
3-229-å
4-165-¥
5-189-½
6-44-,
7-32-
8-119-w
9-111-o
10-114-r
11-108-l
12-100-d
原因:用下标索引字符串可以访问单个字节,而不是字符,range遍历的是字符
package main
import "fmt"
func main() {
//直接用+,无法与数字连接
s := "hello"
s += "world"
fmt.Println(s)
//格式化拼接,可以连接数字
s1 := fmt.Sprintf("%s-%d", "hello", 888)
fmt.Println(s1)
}
输出
helloworld
hello-888
在 go 语言中,字符串实是一个不可改变的字节序列,包含一个指针与长度字段
字符串是一个不可改变的字节序列
字符串并不支持cap(),会编译报错,原因是底层结构只有Len字段
字符串range 遍历输出的是rune(int32)值,可能是utf8值或者ASCII,用下标遍历输出的是字符值