在 Go 語言中,string 類型的底層結構是一個結構體,包含兩個字段:一個指向字節數組的指針和該字節數組的長度。以下是其在 Go 源碼中的大致定義:
type stringStruct struct {str unsafe.Pointerlen int
}
str:這是一個指向字節數組的指針,該數組存儲著字符串的實際內容。 len:它表示字符串的長度,也就是字節數組中字節的數量。 當你創建一個字符串時,Go 語言會在內存里分配一塊連續的區域,用來存放字符串的字節序列。字符串一旦創建,其內容就不可變,而且這塊內存區域的大小等同于字符串的長度。 例如: s := "hello" 在這個例子中,Go 語言會分配一塊大小為 5 字節的內存區域,用來存放字符串 "hello" 的字節序列。stringStruct 中的 str 指針會指向這塊內存區域的起始地址,len 字段的值則為 5。 當你修改字符串時,Go 語言會重新分配一塊內存區域,并將原來的字符串內容復制到新區域中。 例如: s = s + " world" 在這個例子中,Go 語言會重新分配一塊大小為 11 字節的內存區域,并將原來的字符串 "hello" 的內容復制到新區域中,再追加上 " world" 字符串的字節序列。stringStruct 中的 str 指針會指向這塊內存區域的起始地址,len 字段的值則為 11。j
舉個例子測試下:
package mainimport ("fmt""unsafe"
)func main() {s := "hello"// 打印字符串的長度fmt.Printf("Length of s: %d\n", len(s)) // Length of s: 5// 打印字符串的底層結構strStruct := (*struct {str unsafe.Pointerlen int})(unsafe.Pointer(&s))fmt.Printf("Pointer to underlying data: %p\n", strStruct.str) // Pointer to underlying data: 0xa60caffmt.Printf("Length of underlying data: %d\n", strStruct.len) // Length of underlying data: 5fmt.Printf(" %v,%v\n", &s, strStruct) // 0xc000026070,&{0xa60caf 5}// 嘗試修改字符串s = s + " world"// 打印新字符串的底層結構newStrStruct := (*struct {str unsafe.Pointerlen int})(unsafe.Pointer(&s))fmt.Printf("Pointer to new underlying data: %p\n", newStrStruct.str) // Pointer to new underlying data: 0xc00000a0e0fmt.Printf("Length of new underlying data: %d\n", newStrStruct.len) // Length of new underlying data: 11fmt.Printf(" %v,%v\n", &s, newStrStruct) // 0xc000026070,&{0xc00000a0e0 11}
}