string是一个8位字节的集合,通常但不一定代表UTF-8编码的文本。string可以为空,但是不能为nilstring的值是不能改变的。string类型本质也是一个结构体,底层本质就是一个byte类型的数组。 byte就是uint8的别名,它是用来区分字节值和8位无符号整数值

string与[]byte的区别

对于[]bytestring而言,两者之间最大的区别就是string的值不能改变。string在底层都是结构体stringStruct{str: str_point, len: str_len}string结构体的str指针指向的是一个字符常量的地址, 这个地址里面的内容是不可以被改变的,因为它是只读的,但是这个指针可以指向不同的地址。 string的好处:以在不加锁的控制下,多次使用同一字符串,在保证高效共享的情况下而不用担心安全问题

对于[]byte来说,以下操作是可行的:

1
2
b := []byte("hello world")
b[1] = 'i'

string修改操作是被禁止的:

1
2
s := "hello world"
s[1] = 'i'

string支持这样的操作:

1
2
s := "hello world"
s = "iello world"

string与[]byte的互相转化

string的底层数据结构类型:

1
2
3
4
type stringStruct struct {
    str unsafe.Pointer
    len int
}

[]byte对应的底层数据结构(本质上是个slice):

1
2
3
4
5
type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

两者对应的结构非常相似。

标准转化

1
2
3
4
5
6
// string to []byte
s1 := "hello world"
b := []byte(s1)

// []byte to string
s2 := string(b)

强制转化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func String2Bytes(s string) []byte {
     sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	 bh := reflect.SliceHeader{
		 Data: sh.Data,
         Len:  sh.Len,
         Cap:  sh.Len,
    }
    return *(*[]byte)(unsafe.Pointer(&bh))
}

func Bytes2String(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

为什么强转换性能会比标准转换好?

标准转换,无论是从[]bytestring还是string[]byte都会涉及底层数组的拷贝。 而强转换是直接替换指针的指向,从而使得string[]byte指向同一个底层数组。这样,当然后者的性能会更好

强转的坑

如下示例

1
2
3
a := "hello"
b := String2Bytes(a)
b[0] = 'H'

astring类型,值是不可修改的。通过强转换将a的底层数组赋给b,而b是一个[]byte类型,它的值是可以修改的, 所以这时对底层数组的值进行修改,将会造成严重的错误(通过defer+recover也不能捕获)。

todo 新版本的处理

参考文档: https://mp.weixin.qq.com/s/REtrm292mlIwzaYtJrV7bw https://mp.weixin.qq.com/s?__biz=MzAxMTA4Njc0OQ==&mid=2651439171&idx=3&sn=5c3a668490c32233e7626eac28418c2c&chksm=80bb1eb1b7cc97a7b6137c6a7b8e334cd00b304062216c43657962d8efad17b56e99766279bb&scene=21#wechat_redirect