0


Go | string与UTF8编码

字符表示

使用字符编号对照表,即收录很多字符,然后给他们一一编号。

字符集促进了字符与二进制的合作

ASCII字符集(1967年)只收录了128个字符,扩展字符集也就只有256个
英文字符、阿拉伯数字、西文符、控制字符

GB2312(1980年)添加了简体中文、拉丁字母、日文假名

BIG5(1984年) 添加了繁体字,但是依旧有很多字符没有被收录

GB13000.1(1993年) 添加了中日韩

GBK(1995年) 不支持韩文

GB18030(2000) 更多兼容

与其不断退出更多字符的字符集,莫不如本着全球化统一标准的目的,制作一个通用字符集。这个字符集就是Unicode

Unicode(1990-1994)实现了跨区语言跨平台的文本转换与处理

如何划分字符边界

  • 直接照搬Unicode字符集进行拼凑,显然行不通,无法区分字符边界

定长编码

不管编号多大多小,统一按最长的来,位数不够高位补零。

虽然字符边界解决了,但是有些浪费内存。而且字符集收录的越多,字符跨度越大,定长编码造成的浪费就越显著

变长编码(UTF-8)

Go 语言默认的编码方式

小编号少占字节,大编号多占字节

那如何划分边界呢?
编号编码模板–[0,127]0???占一字节,且最高位标识为0[128,2047]110??? 10???占用两个字节,且有固定标识位110和10[2048,65535]1110??? 10??? 10???占用三字节,且有固定标识位1110和10[65536,…]11110??? 10??? …三个以上字节也遵循这样的规则
除了固定标识位,其他的就是该字符的二进制编号

字符串类型的变量结构

源码包

src/runtime/string.go:stringStruct

定义了

string

的数据结构:

type stringStruct struct{
    str unsafe.Pointer
    lenint}

string 数据结构存放两个东西

  • stringStruct.str:字符串的首地址
  • stringStruct.len:字符串的长度

字符串的存储要用“字符集”配合“编码”才行

字符串构建过程是先根据字符串构建stringStruct,再转换成string。转换的源码如下:

funcgostringnocopy(str *byte)string{// 根据字符串地址构建string
    ss := stringStruct{str: unsafe.Pointer(str),len:findnull(str)}// 先构造stringStruct
    s :=*(*string)(unsafe.Pointer(&ss))// 再将stringStruct转换成stringreturn s
}

string在runtime包中就是stringStruct,对外呈现叫做string。

为什么字符串不允许修改?

字符串不能够被修改,所以这样定义的字符串内容被分配到只读内存段,而不是堆或栈上

字符串变量是可以共享底层字符串内容的,如果对字符串修改,那么后果是无法估计的
字符串变量共享底层字符串

内存中这些读、写、执行等权限,是为了保护程序的正常运行

如果非要修改

  • str = “hello” 使str重新分配内存,便不会修改原内存
  • bs := ([]byte)(str) bs[2] = ‘o’ 可以把变量强制类型转换成字节slice,这样会为slice变量重新分配一段内存,并且会拷贝原来字符串的内容

注:了解slice的结构并且学会使用unsafe包,就可以让slice依然使用原来字符串指向的这段内存,这样虽然转换了内存,但是依然不能修改这段只读内存的内容

标签:

本文转载自: https://blog.csdn.net/Lin_Bolun/article/details/116854849
版权归原作者 Lindbergh_ 所有, 如有侵权,请联系我们删除。

“Go | string与UTF8编码”的评论:

还没有评论