目录
一、string数据结构
type stringStruct struct {
str unsafe.Pointer
len int
}
str:字符串的首地址;
len:字符串的长度;
二、切片和字符串转换
1. byte切片转string
需要一次内存拷贝,转换过程:
1)【申请空间】:跟据切片的长度申请内存空间,假设内存地址为p,切片长度为len(b);
2)【构建string】:string.str = p;string.len = len;
3)【拷贝数据】:切片中数据拷贝到新申请的内存空间;
2. string转byte切片
也需要一次内存拷贝,其过程如下:
1)【申请内存】:申请切片内存空间;
2)【数据拷贝】:将string拷贝到切片;
3. byte切片转换成string一定会拷贝内存吗?
只是临时需要字符串的场景下,byte切片转换成string时并不会拷贝内存,而是直接返回一个string:
1)使用m[string(b)]来查找map(map是string为key,临时把切片b转成string);
2)字符串拼接,如”<” + “string(b)” + “>”;
3)字符串比较:string(b) == “foo”
4. string和byte切片适用场景
string 擅长的场景:
1)需要字符串比较的场景;
2)不需要nil字符串的场景;
byte切片擅长的场景:
1)修改字符串的场景;
2)函数返回值,需要用nil表示含义的场景;
3)需要切片操作的场景;
三、字符串拼接
【申请内存】第一次遍历获取总的字符串长度,据此申请内存;
【数据拷贝】第二次遍历会把字符串逐个拷贝过去;
func concatstrings(a []string) string { // 字符串拼接
length := 0 // 拼接后总的字符串长度
for _, str := range a {
length += length(str)
}
s, b := rawstring(length) // 生成指定大小的字符串,返回一个string和切片,二者共享内存空间
for _, str := range a {
copy(b, str) // string无法修改,只能通过切片修改
b = b[len(str):]
}
return s
}
func rawstring(size int) (s string, b []byte) { // 生成一个新的string,返回的string和切片共享相同的空间
p := mallocgc(uintptr(size), nil, false)
stringStructOf(&s).str = p
stringStructOf(&s).len = size
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
return
}