Go语言不但拥有可以独立代表Unicode字符类型rune,而且还可以对字符串值进行Unicode字符拆分的for语言
_

Strings包

**

string 类型

  • 在Golang语言中string类型的值是不可变的
  1. 在低层,一个string类型的内容会被存储到一块连续的内存空间中,同时这块内容容纳的字节数也会被记录下来(用于表示string类型内容值的长度)
  • 裁剪操作可使用切片表达式
  1. 内存看成是字节数组,而相应string类型的值则包含字节数组头部的指针值
  2. 在string类型值上应用切片表达式,就相当于在底层字节数组上做切片
  • 拼接操作可使用操作符 + 实现
  1. 在字符串拼接的时候,Go语言会把所有待拼接字符串拷贝到一个足够打的新的内存空间中
  2. 然后把持有指针值的string值返回
  3. 因此在程序过多的出现拼接string类型的值会影响性能
  • 虽然string值内部持有指针值,但其类型仍然属于值类型
  • string值会在底层与它的所有副本共用同一个字节数组,由于字节数组永远不会改变,所有这样做是绝对安全的

**

strings包中拥有不少 Unicode 包的程序实体

  • strings.Builder 类型的 WriteRune 方法
  • strings.Reader 类型的 ReadRune 方法

**

strings.Builder 类型

什么是Builder类型?

  • Builder值中有一个用于承载内容的容器
  • 以byte为元素类型的切片
  • 字节切片底层的数组就是一个字节数组,因此它与string类型的存储方式是一致的

优势点:

  • 已经存在的内容不可变,但可拼接更多的内容
  • 减少内存分配和拷贝的次数(与string值相比,Builder值的优势在于字符串拼接)
  • 可将内容重置,可重用值

约束点:

  • 一旦被真正使用后就不可再被复制
  1. 一旦调用拼接方法或者扩容方法就意味值Builder类型的值被使用了
  2. 一旦被使用就意味着不能对该值的副本(复制)进行操作,否则会引发panic

复制方式,包括但不限于在函数间传递值、通过通道传递值、把值赋予变量等等

  1. var builder1 strings.Builder
  2. builder1.Grow(1)
  3. builder3 := builder1
  4. //builder3.Grow(1) // 这里会引发panic。
  5. _ = builder3
  • Builder类型的值不能被复制使用,但是可通过指针使用
  1. package main
  2. import "strings"
  3. func main() {
  4. var builder1 strings.Builder
  5. builder1.Grow(1) // 使用
  6. f2 := func(bp *strings.Builder) {
  7. (*bp).Grow(1) // 通过指针改变值
  8. _ = builder4
  9. }
  10. f2(&builder1)
  11. }

高效读取数据的 strings.Reader

  • 与 strings.Builder类型相反,strings.Reader类型是为了高效读取字符串而存在
  • strings.Reader类型依靠已读取字节数的计数,从而实现快速读取

    已读取字节的计数属于Reader值的内部结构,但是可以计算

  1. reader1 := strings.NewReader(
  2. "NewReader returns a new Reader reading from s. " +
  3. "It is similar to bytes.NewBufferString but more efficient and read-only.")
  4. fmt.Printf("The size of reader: %d\n", reader1.Size())
  5. fmt.Printf("The reading index in reader: %d\n", reader1.Size()-int64(reader1.Len()))

ReadAt方法是个例外,它既不会依据一度计数进行读取也不会在读取后更新已读计数

  1. reader1 := strings.NewReader(
  2. "NewReader returns a new Reader reading from s. " +
  3. "It is similar to bytes.NewBufferString but more efficient and read-only.")
  4. buf2 := make([]byte, 21)
  5. offset1 := int64(64)
  6. n, _ = reader1.ReadAt(buf2, offset1)
  7. fmt.Printf("%d bytes were read. (call ReadAt, offset: %d)\n", n, offset1)
  8. fmt.Printf("The reading index in reader: %d\n",
  9. reader1.Size()-int64(reader1.Len()))
  10. fmt.Println()