string內存結構
Go string 實現原理剖析(你真的了解string嗎)
//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不可修改的約定。
[strings包][https://www.linkinstar.wiki/2019/06/20/golang/source-code/strings-go-source-code/]
ToUpper
Replace
Index
hashStr //use in Rabin-Karp algorithm.
indexRabinKarp
genSplit
countGeneric