基本性质
-
string
类型实际上是一个双字结构,即一个指向实际数据的指针和记录字符串长度的整数- 因此字符串是根据长度,而非特殊字符
\0
判定结尾
- 因此字符串是根据长度,而非特殊字符
-
空字符串是
""
而不是nil
-
字符串不可变
string[0] = 'a'
会导致编译错误- 只能先转换为
[]byte
再转换回去,或者使用strings.Replace
函数
-
获取字符串中某个字节的地址(如
&str[0]
)的行为是非法的 -
相同的字符串常量会在底层共用同一个字节数组
- 由于字节数组永远不会被改变,所以这样做是安全的
-
直接把一个整数值转换为一个string类型的值是可行的:
string(100) // d
- 被转换的整数值应该可以代表一个有效的 Unicode 代码点,否则转换的结果将会是"�"
- 字符’�’的 Unicode 代码点是U+FFFD
- 它是 Unicode 标准中定义的 Replacement Character,专用于替换那些未知的、不被认可的以及无法展示的字符
- 在实际工作中,我们在排查问题时可能会遇到�,你需要知道这可能是由于什么引起的
- 字符’�’的 Unicode 代码点是U+FFFD
- 被转换的整数值应该可以代表一个有效的 Unicode 代码点,否则转换的结果将会是"�"
-
可以直接把字符串追加到字符切片后面
var b []byte
var s string
b = append(b, s...)
- 利用
strings.Reader
可以高效多次分批读取一个字符串- Reader值实现高效读取的关键就在于它内部的已读计数。计数的值就代表着下一次读取的起始索引位置
- 字符串拼接
strings.Builder
类型的变量只要被调用了拼接或扩容方法(非零值),就不能被复制- 否则在任何副本上再调用上述方法就都会引发 panic
- 这里所说的复制方式,包括但不限于在函数间传递值、通过通道传递值、把值赋予变量等
- 虽然已使用的Builder值不能再被复制,但是它的指针值却可以
- 但如果Builder值被多方同时操作,那么其中的内容就很可能会产生并发安全问题
- 原因: 正是由于已使用的Builder值不能再被复制,所以肯定不会出现多个Builder值中的内容容器(也就是那个字节切片)共用一个底层字节数组的情况。这样也就避免了多个同源的Builder值在拼接内容时可能产生的冲突问题
func (b *Builder) copyCheck() {
if b.addr == nil {
// This hack works around a failing of Go's escape analysis
// that was causing b to escape and be heap allocated.
// See issue 23382.
// TODO: once issue 7921 is fixed, this should be reverted to
// just "b.addr = b".
b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
}
strings.Reader
和bytes.Buffer
的Len()
方法返回的都是内容容器中未被读取部分的长度,而不是已存内容的总长度string
和[]byte
的无拷贝转换- 一个string类型的值在底层就是一个能够表达若干个 UTF-8 编码值的字节序列
string
和[]byte
都是通过一个unsafe.Pointer
类型的字段来持有那个指向了底层字节数组的指针值
func String2Bytes(str string) []byte {
l := len(str)
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: (*(*reflect.StringHeader)(unsafe.Pointer(&str)