首页 > 其他分享 >go基础数据类型 - string的底层

go基础数据类型 - string的底层

时间:2023-11-28 18:26:32浏览次数:27  
标签:string 数据类型 len content rune go 字节

先上一段代码 :

func main() {
	content := "长沙boy"
	content1 := "boy"
	fmt.Printf("content: %d\n", unsafe.Sizeof(content))
	fmt.Printf("content1: %d\n", unsafe.Sizeof(content1))
}

打印的结果:

content: 16
content1: 16

问题1、从这里能看出,这个16基本字符串的内容长短没关系,那是和什么相关?

还是上面那个例子,很多人意识到打印长度,应该换成 len()方法

fmt.Printf("content: %d\n", len(content))
fmt.Printf("content1: %d\n", len(content1))

打印结果:

content: 9
content1: 3

问题2,为什么这个字符长度会是9和3 ?

第一个问题,需要查看下string的底层实现。

string 在runtime中的定义

在runtime的string.go中有定义:

type stringStruct struct {
	str unsafe.Pointer
	len int
}

看到这里,第一个问题有答案了,unsafe.Sizeof` 打印string 为什么是16,

因为打印的是结构体的大小,所以不管什么内容的string,大小都为16,

unsafe.Pointer 和 int 各占8个 ,当然这个和操作系统的位数有关。

小结:

字符串本质是个结构体
str指针指向底层Byte数组
Len表示Byte数组的长度

string的字符串长度

能看出调用 len()打印的长度,就是 stringStruct的len的长度。

验证下:

content := "长沙boy"
// util.StringHeader 以前是放在 reflect反射包中
c := (*util.StringHeader)(unsafe.Pointer(&content))
fmt.Printf("c: %d\n", c.Len)

打印:c: 9

那为什么是9? 不是3或者5?

要引入编码问题:

Unicode

一种统一的字符集

囊括了159种文字的144679个字符

14万个字符至少需要3个字节表示

英文字母均排在前128个

因为,英文字符也会占3个字节,会超出浪费。

UTF-8变长编码

Unicode的一种变长格式

128个US-ASCIl字符只需一个字节编码

西方常用字符需要两个字节

其他宇符需要了个字节,极少需要4个字节

go就是采用这个编码,这样就能解释了,为什么 长沙boy 是9,中文3个,英文每个字母1个。

string的读取

content := "长沙boy"
for i := 0; i < len(content); i++ {
	fmt.Println(content[i])
}
打印:
233
149
191
230
178
153
98
111
121

显然不对,这样字节值。

应该采用这个方式:
 content := "长沙boy"
 for _, c := range content {
	fmt.Printf("%c\n", c)
 }

go底层是采用了 runtime下的 utf-8.go中定义的两个方法:

// encoderune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func encoderune(p []byte, r rune) int {}


  // If the string appears to be incomplete or decoding problems
  // are encountered (runeerror, k + 1) is returned to ensure
  // progress when decoderune is used to iterate over a string.
  func decoderune(s string, k int) (r rune, pos int) {}

能看到值转为了 rune 类型后再进行的。

小结:

对字符串使用len方法得到的是字节数不是字符数
对宇符串直接使用下标访问,得到的是字节
宇符串被range遍历时,被解码成rune类型的字符
UTF-8 编码解码算法位于 runtime/utf8.go

宇符串的切分

    转为rune数组
    切片
    转为 string   
 s=string ([]rune(s)[:3) 取前3个

rune类型是Go语言中的一个基本类型,其实就是一个int32的别名,主要用于表示一个字符类型大于一个字节小于等于4个字节的情况下,特别是中文字符。

标签:string,数据类型,len,content,rune,go,字节
From: https://www.cnblogs.com/studyios/p/17862405.html

相关文章

  • mongoDB操作避坑
    1.首先MongoDB6.0及以上的版本是不带mongoshell的,所以要向用需要自己去下载,然后将压缩包解压到桌面然后复制过去一定是复制过去,要不然mongo的管理员权限不让你复制,  完成之后在这个文件加下的bin中双击后回车就可进入shell界面。2.然后是API操作,这里用的是maven,我们将代......
  • C# 比使用app.config,用自定义的ConnectionString
    usingSystem.Data;usingSystem.Data.SqlClient;usingSystem.IO;usingSystem.Reflection;namespaceAssist{publicclassContextHelper{publicstaticstringConnectionString;publicstaticstringSerializePath=Path.GetDirector......
  • java字符串String类的常用方法
    java字符串String类的常用方法字符串的创建:(1)定义字符串直接赋值,在字符串池中开辟空间()Stringstr1=“Hello”;//在字符串池中写入字符串"hello"Stringstr2=“Hello”;//直接引用字符串池中的"Hello"System.out.println(str1==str2);//地址相同,输出:true(2)使用new关键字调用字......
  • 无涯教程-F# - 数据类型
    F#中的数据类型可以分类如下-整数类型浮点类型文本类型其他类型整体数据类型下表提供了F#的整数数据类型,这些基本上是整数数据类型。F#TypeSizeRangeExampleRemarkssbyte1byte-128to12742y-11y8-bitsignedintegerbyte1byte0to25542uy200uy8-......
  • Django回顾
    提问#0把mysql全都卸载---》5.7版本---》把5.6卸载https://zhuanlan.zhihu.com/p/571585588#1保证能够链接到你同桌mysql 192.168.1.2521关闭防火墙  2知道你同桌ip  3链接:mysql navicate链接    #2保证你的django,你同桌可以访问-ht......
  • 基本数据类型
    【一】基本数据类型引入【1】学习变量的目的学习变量有助于我们在程序中存储和操作数据,提高代码的灵活性和可维护性。通过使用变量,我们可以方便地引用和修改数据,使得程序能够动态地响应不同的输入和条件。【2】学习基本数据类型的目的学习基本数据类型有助于我们理解不同......
  • python脚本中调用django环境
    #在脚本中调用djagno服务importosif__name__=='__main__':#1引入django配置文件os.environ.setdefault('DJANGO_SETTINGS_MODULE','day67.settings')#2让djagno启动importdjangodjango.setup()#3使用表模型fromapp01impor......
  • Go语法糖——简短变量声明“:=”
    参考地鼠文档——GO专家编程中的内容,我总结了关于 :=的几条规则,并以代码举例的运行结果来说明可行性,以避免编程中出现一些陷阱。规则一:不能用于函数外部packagemainimport"fmt"rule:="Shortvariabledeclarations"funcmain(){fmt.Println(rule)}编......
  • Can Pre-Trained Text-to-Image Models Generate Visual Goals for Reinforcement Lea
    概述LearningformtheVoid(LfVoid)根据给定的languageinstruction对observation进行appearance-basedandstructure-based修改得到goalimages,为RL提供奖励信号。提升了example-basedRLmethods,无需rewardfunction或者demonstration就可以解决一些robotcontroltasks问......
  • 秦疆的Java课程笔记:43 流程控制 break、continue、goto
    break:在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。(break也在switch语句中使用)publicclassBreakDemo{publicstaticvoidmain(String[]args){inti=0;while(i<100){......