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))
}
相关文章
|
15天前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
|
16天前
|
Go
Go语言的条件控制语句及循环语句的学习笔记
本文是Go语言的条件控制语句和循环语句的学习笔记,涵盖了if语句、if-else语句、if嵌套语句、switch语句、select语句以及for循环和相关循环控制语句的使用方法。
Go语言的条件控制语句及循环语句的学习笔记
|
16天前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
1月前
|
人工智能 算法 搜索推荐
Go学习笔记-代码调
近年来,人工智能技术飞速发展,Cody作为由Sourcegraph开发的一款AI驱动编码助手,应运而生。它不仅提供代码预测与补全,还能深度理解代码上下文,为开发者提供准确建议,提升编码效率和质量。Cody能识别潜在错误并提出修复建议,缩短调试时间,同时进行智能代码审查,帮助优化代码结构和风格。未来,随着AI技术进步,Cody将不断学习优化,成为开发者不可或缺的伙伴,推动编程领域的创新与发展。
25 0
|
2月前
|
Go
Go - 学习 grpc.Dial(target string, opts …DialOption) 的写法
Go - 学习 grpc.Dial(target string, opts …DialOption) 的写法
47 12
|
2月前
|
存储 缓存 NoSQL
深入理解Redis数据类型String原理
本文深入探讨了Redis中String数据类型的实现原理和使用场景,基于Redis 5.0版本进行分析。
深入理解Redis数据类型String原理
|
2月前
|
存储 安全 Go
Go 面试题:string 是线程安全的吗?
Go 面试题:string 是线程安全的吗?
|
2月前
|
缓存 Java 编译器
Go 中的内存布局和分配原理
Go 中的内存布局和分配原理
|
2月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
33 0
|
2月前
|
存储 人工智能 JSON
深入理解 go reflect - 反射基本原理
深入理解 go reflect - 反射基本原理
43 0

热门文章

最新文章