Go系列 string、bytes、rune的区别

计算机如何表示字符

计算机是二进制的,字符最终也是转换成二进制保存起来的。字符集就是定义字符对应的数值。 Unicode是一个字符集,为每一个字符规定一个用来表示该字符的数字,可是并无规定该数字的二进制保存方式,utf8规定了对于unicode值的二进制保存方式。bash

utf8是可变长度字符编码,不一样的字符会对应不一样大小的存储方式,好比"a"字符(unicode值97)用1个字节,而"中"字符(unicode值20013)则用3个字节。字符的unicode值决定了字符须要用多少字节表示函数

什么是string?

Go语言中,string就是只读的采用utf8编码的字节切片(slice) 所以用len函数获取到的长度并非字符个数,而是字节个数。 for循环遍历输出的也是各个字节。工具

a := "Randal";
for i := 0; i < len(a); i++ {
 fmt.Printf("%x ", a[i])
 fmt.Printf("%c ", a[i])
}
// 输出结果
52 61 6e 64 61 6c
Randal
复制代码
a := "中国";
fmt.Println(len(a))
for i := 0; i < len(a); i++ {
 fmt.Printf("%x ", a[i])
}
for i := 0; i < len(a); i++ {
 fmt.Printf("%c ", a[i])
}

// 输出结果
6
E4 B8 AD E5 9B BD
中å½
复制代码

fmt.Printf函数支持从一个表达式列表生成格式化的输出,它的第一个参数是格式化指示字符串,由它指定其余参数如何格式化。其中%c,用于输出字符(Unicode码点),码点是字符的unicode值。 因为go采用的是utf8编码,而“中”的utf8编码是E4 B8 AD(所表示的unicode值是U+4E2D), https://unicode-table.com/en/00E4/ 经过这个连接能够看到ä的unicode编码就是U+00E4。编码

从上面的例子中能够看出当字符的utf8编码超过1个字节的时候格式化输出单个字符就会出现乱码的状况,若是但愿解决乱码问题就要用到rune了spa

什么是rune?

rune是int32的别名,表明字符的Unicode编码,采用4个字节存储,将string转成rune就意味着任何一个字符都用4个字节来存储其unicode值,这样每次遍历的时候返回的就是unicode值,而再也不是字节了,这样就能够解决乱码问题了code

var s string
   s = "中国"
   r := []rune(s)
   for i := 0; i < len(r); i++ {
     fmt.Printf("%x", r[i])
   }
   for i := 0; i < len(r); i++ {
     fmt.Printf("%c", r[i])
   }
  // 输出结果
  4e2d 56fd
  中国
复制代码

经过for range对字符串进行遍历时,每次获取到的对象都是rune类型的,所以下面的方式也能够解决乱码问题cdn

var s string
   s = "中国"
   for _, item := range s {
     fmt.Printf("%c", item)
   }
  // 输出结果
  中国
复制代码

什么是bytes

bytes操做的对象也是字节切片,与string的不可变不一样,byte是可变的,所以string按增量方式构建字符串会致使屡次内存分配和复制,使用bytes就不会于是更高效一点对象

package main
 import (
   "fmt"
   "bytes"
 )
 func main() {
   var s string
   s = "中国"
   var b bytes.Buffer
   b.WriteString("中国")
   for i := 0; i < 10; i++ {
     s += "a"
     b.WriteString("a")
   }
   fmt.Println(s)
   fmt.Println(b.String())
 }
复制代码

参考资料与工具

在线utf8转换 String Data Type in Go byte vs string in Goblog

相关文章
相关标签/搜索