标签:info ext range 而不是 通过 为什么 ntp 大小 href
//builtin包对string的描述
// string is the set of all strings of 8-bit bytes, conventionally but not
// necessarily representing UTF-8-encoded text. A string may be empty, but
// not nil. Values of string type are immutable.
type string string
- 默认零值是"" , 而不是nil
- 不可变(值存储在只读内存区)
- stings数据结构的定义:
src/runtime/string.go: stringStruct (对外呈现string)
type stringStruct struct {
str unsafe.Pointer //str首地址
len int //str长度
}
// str构造过程: 先构造stringStruct,然后将stringStruct转为str返回
var s string
s = "mao"
func gostringnocopy(str *byte) string { // 跟据字符串地址构建string
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)} // 先构造stringStruct
s := *(*string)(unsafe.Pointer(&ss)) // 再将stringStruct转换成string
return s
}
// []byte转string(转换需要一次内存拷贝)
func GetStringBySlice(s []byte) string {
return string(s)
}
1. 根据切片长度申请足够内存地址空间
2. 构建string
3. 拷贝数据
// string转换[]byte(转换需要一次内存拷贝)
func GetSliceByString(str string) []byte {
return []byte(str)
}
1.申请内存地址空间
2.拷贝数据
// 字符串拼接
str := "Str1" + "Str2" + "Str3"
性能较好:
新字符串的内存空间是一次分配完成的,
所以性能消耗主要在拷贝数据上。
一个拼接语句的字符串编译时都会被存放到一个切片中,拼接过程需要遍历两次切片,
1. 第一次遍历获取总的字符串长度,据此申请内存,
2. 第二次遍历会把字符串逐个拷贝过去。
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
}
// 为什么字符串不允许修改?
像C++语言中的string,其本身拥有内存空间,修改string是支持的。
但Go的实现中,string**不包含内存空间,只有一个内存的指针**,
这样做的好处是string变得非常轻量,可以很方便的进行传递而不用担心内存拷贝。
因为string通常指向字符串字面量,**而字符串字面量存储位置是只读段,而不是堆或栈上,**
所以才有了string不可修改的约定。
标签:info ext range 而不是 通过 为什么 ntp 大小 href
原文地址:https://www.cnblogs.com/iiiiiher/p/12153429.html