1、字符串的存储原理
string 数据结构:源码包src/runtime/string.go:stringStruct定义了string的数据结构:
ype stringStruct struct {
str unsafe.Pointer
len 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)) // 苑昊 string
var b = []byte(s) // 默认用uft-8进行编码
fmt.Println(b,reflect.TypeOf(b)) // [232 139 145 230 152 138] []uint8
s := "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转为string
fmt.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])
}
// 如果是中文呢,可以使用range
s2 := "我爱你中国"
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"