1、字符串的存储原理

string 数据结构:源码包src/runtime/string.go:stringStruct定义了string的数据结构:
ype stringStruct struct {str unsafe.Pointerlen int}
其数据结构很简单:
- stringStruct.str:字符串的首地址;
- stringStruct.len:字符串的长度;
string数据结构跟切片有些类似,只不过切片还有一个表示容量的成员,事实上string和切片,准确的说是byte切片经常发生转换。这个后面再详细介绍。
s4 := "hello"s5 := s4[:]s6 := s4[1:]fmt.Println(&s4, (*reflect.StringHeader)(unsafe.Pointer(&s4)))fmt.Println(&s5, (*reflect.StringHeader)(unsafe.Pointer(&s5)))fmt.Println(&s6, (*reflect.StringHeader)(unsafe.Pointer(&s6)))
/*A string type represents the set of string values. A string value is a (possibly empty) sequence of bytes. Strings are immutable: once created, it is impossible to change the contents of a string. The predeclared string type is string.The length of a string s (its size in bytes) can be discovered using the built-in function len. The length is a compile-time constant if the string is a constant. A string's bytes can be accessed by integer indices 0 through len(s)-1. It is illegal to take the address of such an element; if s[i] is the i'th byte of a string, &s[i] is invalid.*/
字符串类型表示字符串值的集合。字符串值是一个字节序列(可能为空)。字符串是不可变的:一旦创建,就不可能改变字符串的内容。预先声明的字符串类型是string。
字符串s的长度(以字节为单位的大小)可以使用内置函数len来发现。如果字符串是常量,则长度为编译时常量。字符串的字节可以通过索引0到len(s)-1的整数来访问。取这样一个元素的地址是非法的;如果s[i]是字符串的第i个字节,&s[i]是无效的。
2、字符串和字节串
字节数组,就是一个数组,里面每一个元素都是字符,字符又跟字节划等号。所以字符串和字节数组之间可以相互转化。
// (1) 字符串类型(string) 转为字节串类型([]byte)var s = "高高"fmt.Println(s,reflect.TypeOf(s)) // 苑昊 stringvar b = []byte(s) // 默认用uft-8进行编码fmt.Println(b,reflect.TypeOf(b)) // [232 139 145 230 152 138] []uint8s := "Hello, 世界"r1 := []byte(s)r2 := []rune(s)fmt.Println(r1) // 输出:[72 101 108 108 111 44 32 228 184 150 231 149 140]fmt.Println(r2) // 输出:[72 101 108 108 111 44 32 19990 30028]// (2) byte转为stringfmt.Println(string(b))var data = []byte{121,117,97,110}fmt.Println(string(data)) // yuan
这里的转化不是将string结构体中指向的byte切片直接做赋值操作,而是通过copy实现的,在数据量比较大时,这里的转化会比较耗费内存空间。
3、字符串的遍历
var s1 = "hello world"for i := 0; i < len(s1); i++ {//fmt.Println(s1[i])fmt.Printf("%d:%c\n",s1[i],s1[i])}// 如果是中文呢,可以使用ranges2 := "我爱你中国"for byte_index, value := range s2 {fmt.Printf("%d %c\n", byte_index,value)}// 可以通过代码 len([]rune(s)) 来获得字符串中字符的数量, 但使用 utf8.RuneCountInString(s) 效率会更高一点.fmt.Println(len(s2) )fmt.Println(len([]rune(s2)) )fmt.Println(utf8.RuneCountInString(s2))
小练习:
// 将字符串 "hello" 转换为 "cello":s := "hello"c := []byte(s)c[0] = 'c's2 := string(c) //s2 == "cello"
