Golang底层原理剖析之string类型与字符编码

简介: Golang底层原理剖析之string类型与字符编码

Unicode简介

Unicode记录着世界上所有字符对应的一个数字,它仅仅只是一个字符集,规定了符合对应的二进制代码,至于这个二进制代码如何存储则没有任何规定。

Unicode 没有规定字符对应的二进制码如何存储。以汉字“汉”为例,它的 Unicode 码点是 0x6c49,对应的二进制数是 110110001001001,二进制数有 15 位,这也就说明了它至少需要 2 个字节来表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 个字节或者 4 个字节,甚至更多字节来表示了。

这就导致了一些问题,计算机怎么知道你这个 2 个字节表示的是一个字符,而不是分别表示两个字符呢?这里我们可能会想到,那就取个最大的,假如 Unicode 中最大的字符用 4 字节就可以表示了,那么我们就将所有的字符都用 4 个字节来表示,不够的就往前面补 0。这样确实可以解决编码问题,但是却造成了空间的极大浪费,如果是一个英文文档,那文件大小就大出了 3 倍,这显然是无法接受的

于是,为了较好的解决 Unicode 的编码问题, UTF-8 和 UTF-16 两种当前比较流行的编码方式诞生了。当然还有一个 UTF-32 的编码方式,也就是上述那种定长编码,字符统一使用 4 个字节,虽然看似方便,但是却不如另外两种编码方式使用广泛。

Unicode 编码方案之UTF-8

UTF-8 是目前互联网上使用最广泛的一种 Unicode 编码方式,它的最大特点就是可变长。它可以使用 1 - 4 个字节表示一个字符,根据字符的不同变换长度。编码规则如下:

  1. 对于单个字节的字符,第一位设为 0,后面的 7 位对应这个字符的 Unicode 码点。因此,对于英文中的 0 - 127 号字符,与 ASCII 码完全相同。这意味着 ASCII 码那个年代的文档用 UTF-8 编码打开完全没有问题。
  2. 对于需要使用 N 个字节来表示的字符(N > 1),第一个字节的前 N 位都设为 1,第 N + 1 位设为0,剩余的 N - 1 个字节的前两位都设位 10,剩下的二进制位则使用这个字符的 Unicode 码点来填充。


  1. 字符‘e’的编号是101,那么它对应的UTF-8的编码模板是0???,接着将101转成二进制填入,则‘e’的UTF-8的二进制编码为01100101
  2. [1110 0100,10 111000,10 010110]来看第一个字节,它以1110开头,说明这一字符占用三个字节,它要和后面2个字节共同表示一个字符,除去这么标识位,把剩下的组合起来,就得到该字符的二进制编号[0100111000010110]转换成十进制19990,在Unicode中对应汉字‘世’
  3. ‘界’在Unicode字符集中编号为30028,在[2048,65535]这个区间,要使用[1110???,10???,10???]这个模板,把30028转换成二进制[0111010101001100],再填入模板中

  1. 编码完成!

string类型

string结构

go语言中默认使用的是UTF-8编码

string由两部分组成,一部分是指向字符串起始地址的指针,另一部分是 字节个数len 注意不是字符个数,是字节个数!这个数据类型占用16B空间,指向字符串起始地址的指针和存在字节个数的整型分别是8B


go里面的字符串变量就长这样

func main() {
  s1 := "eggo世界"
  fmt.Println(s1)
  fmt.Println("len=", len(s1))
}
$ go run main.go
eggo世界
len= 10

string注意点

  1. string中的内容不能被修改,go语言认为字符串内容是不会被修改的,编译器会把字符串内容分配到只读内存段
s1 := "eggo世界"
s1[2]='w' //err,go语言认为字符串内容是不会被修改的
//编译器会把"eggo世界"这样的字符串内容分配到只读内存段
  1. 可以把string当作字节切片的参数,这样会为slice变量重新分配一段内存,并且会拷贝原来字符串的内容
bs:=[]byte(s1)
bs[2]='w'
  1. string可能为空,但不会是nil


目录
相关文章
|
13天前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
76 29
|
11天前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
|
1月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
50 4
|
1月前
|
存储 分布式计算 NoSQL
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
27 3
|
2月前
|
Go
Golang语言基础之接口(interface)及类型断言
这篇文章是关于Go语言中接口(interface)及类型断言的详细教程,涵盖了接口的概念、定义、实现、使用注意事项以及类型断言的多种场景和方法。
37 4
|
3月前
|
算法 NoSQL 关系型数据库
熔断原理与实现Golang版
熔断原理与实现Golang版
|
3月前
|
存储 关系型数据库 Go
SOLID原理:用Golang的例子来解释
SOLID原理:用Golang的例子来解释
|
3月前
|
SQL 分布式计算 DataWorks
DataWorks产品使用合集之如何将STRING类型转换为DATETIME类型
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
2月前
|
Go
Golang语言基础数据类型之字符类型
这篇文章介绍了Go语言中的字符类型,包括字符概述、byte和rune类型的定义、转义字符的使用以及如何遍历字符串获取字符的示例。
15 0
|
3月前
|
存储 Go 索引
Golang 中的 String、rune 和 byte
Golang 中的 String、rune 和 byte