Go学习笔记-String底层实现原理

简介: Go学习笔记-String底层实现原理

1、字符集

  • 计算机里1bit可以是0也可以是1
  • 8bit组成1byte,全为0时表示数字0,全为1时表示数字255
  • 2byte可以表示65536个数字,更多字节数可以表示更大的数字范围
  • 字符如何表示呢?
  • ASCII字符集:一共收录了128个字符,其扩展字符集也只有256个(包括英文字母、阿拉伯数字、西文字、控制字符)
  • GB2312:包括了简体中文、拉丁字母、日文假名等等
  • BIG5:包括了繁体字等

  • unicode:于1990年开始研发,1994年正式公布,全球统一化字符编码

2、如何表示混合字符

  • 比如"abc字母歌"这种字符如何存储呢?
  • 如果直接用unicode字符集表示,如下图

func main() {
    //string转化为unicode编码切片
    str := "hello,world世界"
    unicode := []rune(str)
    //打印unicode编码
    fmt.Println(unicode)
    for _, v := range unicode {
          //打印二进制
          fmt.Printf("%b\n", v)
    }
}
  • 问题来了
  • 这么多二进制编码有长有短,你怎么知道哪个是哪个呢?
  • 所以就会有字符边界划分的问题?
  • 定长编码可以解决这个问题,但是确实有点浪费空间

  • UTF-8编码:它它是一种变长编码,能有效地解决上述问题,可以根据字符大小范围指定字符边界
  • 0-127之间的,占用1字节,以0标识在字节开头
  • 128-2047之间的,占用2字节,以110和10标识在字节开头
  • 2048-65535之间的,占用3字节,分别以1110、10、10标识在字节开头
  • 以此类推,更多字节的开头都遵循这样的规则

3、Go语言string

  • Go语言默认采用UTF-8编码
func main() {
   //string转化为unicode编码切片
   str := "hello,world世界"
   //打印str的utf-8二进制编码
   strSlice := []byte(str)
   for _, v := range strSlice {
      fmt.Printf("%b\n", v)
   }
}
/*
1101000   -    h
1100101   -    e
1101100   -    l
1101100   -    l
1101111   -    o
101100    -    ,
1110111   -    w
1101111   -    o
1110010   -    r
1101100   -    l
1100100   -    d
11100100 10111000 10010110   - 世
11100111 10010101 10001100   - 界
*/
  • Go语言中上述的 str 变量是什么样的结构呢?
  • 对于string变量,Go语言认为它不可被修改,所以string变量会记录执行只读字符串的内存起始地址
  • 如何找到字符内存地址的结尾地址呢?在C语言中,会在字符的结尾带上\0,但这样就不能写入\0本身这种字符了
  • 为了要找到结尾标识,go语言会在变量后面标识只读字符的字节数

  • string底层数据结构
type stringStruct struct {
    str unsafe.Pointer    // 底层数组指针
    len int                // 字符串长度,可以通过 len(string) 返回
}
  • 如何修改字符串内容呢?
  • slice底层数据结构
type slice struct {
    array unsafe.Pointer    // 底层数组指针,真正存放数据的地方
    len   int                // 切片长度,通过 len(slice) 返回
    cap   int                // 切片容量,通过 cap(slice) 返回
}
  • 可以把字符串变量的值赋值给[]byte这样的切片,会给变量从新分配内存,并且会拷贝字符对应的utf-8编码到切片中
  • 如何使用实现 []byte 和字符串之间的零拷贝转换?
func StringToBytes(str string) []byte {
    var b []byte
    // 切片的底层数组、len字段,指向字符串的底层数组,len字段
    *(*string)(unsafe.Pointer(&b)) = str
    // 切片的 cap 字段赋值为 len(str)的长度,切片的指针、len 字段各占八个字节,直接偏移16个字节
    *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&b)) + 2*uintptr(8))) = len(str)
    return b
}
func BytesToString(data []byte) string {
    // 直接转换
    return *(*string)(unsafe.Pointer(&data))
}
相关文章
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
697 24
|
存储 人工智能 安全
深入理解 go sync.Map - 基本原理
本文介绍了 Go 语言中 `map` 在并发使用时的常见问题及其解决方案,重点对比了 `sync.Mutex`、`sync.RWMutex` 和 `sync.Map` 的性能差异及适用场景。文章指出,普通 `map` 不支持并发读写,容易引发错误;而 `sync.Map` 通过原子操作和优化设计,在某些场景下能显著提升性能。同时详细讲解了 `sync.Map` 的基本用法及其适合的应用环境,如读多写少或不同 goroutine 操作不同键的场景。
622 1
|
算法 Java Go
Go内存原理-GC原理
本文介绍了Go语言中垃圾回收(GC)机制的发展与实现原理,涵盖从标记-清除算法到三色标记法,再到三色标记加混合写屏障的演进过程,重点解析各版本GC的核心思想、优缺点及性能优化方向。
516 4
|
安全 Go 开发者
Go语言之切片的原理与用法 - 《Go语言实战指南》
切片(slice)是Go语言中用于处理变长数据集合的核心结构,基于数组的轻量级抽象,具有灵活高效的特点。切片本质是一个三元组:指向底层数组的指针、长度(len)和容量(cap)。本文详细介绍了切片的声明与初始化方式、基本操作(如访问、修改、遍历)、长度与容量的区别、自动扩容机制、共享与副本处理、引用类型特性以及常见陷阱。通过理解切片的底层原理,开发者可以更高效地使用这一数据结构,优化代码性能。
494 13
|
人工智能 Go
[go]Slice 切片原理
本文详细介绍了Go语言中的切片(slice)数据结构,包括其定义、创建方式、扩容机制及常见操作。切片是一种动态数组,依托底层数组实现,具有灵活的扩容和传递特性。文章解析了切片的内部结构(包含指向底层数组的指针、长度和容量),并探讨了通过`make`创建切片、基于数组生成切片以及切片扩容的规则。此外,还分析了`append`函数的工作原理及其可能引发的扩容问题,以及切片拷贝时需要注意的细节。最后,通过典型面试题深入讲解了切片在函数间传递时的行为特点,帮助读者更好地理解和使用Go语言中的切片。
477 0
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
Go语言的条件控制语句及循环语句的学习笔记
本文是Go语言的条件控制语句和循环语句的学习笔记,涵盖了if语句、if-else语句、if嵌套语句、switch语句、select语句以及for循环和相关循环控制语句的使用方法。
Go语言的条件控制语句及循环语句的学习笔记
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
人工智能 算法 搜索推荐
Go学习笔记-代码调
近年来,人工智能技术飞速发展,Cody作为由Sourcegraph开发的一款AI驱动编码助手,应运而生。它不仅提供代码预测与补全,还能深度理解代码上下文,为开发者提供准确建议,提升编码效率和质量。Cody能识别潜在错误并提出修复建议,缩短调试时间,同时进行智能代码审查,帮助优化代码结构和风格。未来,随着AI技术进步,Cody将不断学习优化,成为开发者不可或缺的伙伴,推动编程领域的创新与发展。
237 0
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
385 0