本篇文章为大家展示了Golang中字符串与字节数组的区别是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
字符串是去语言中最常用的基础数据类型之一,虽然字符串往往都被看做是一个整体,但是实际上字符串是一片连续的内存空间,我们也可以将它理解成一个由字符组成的数组,去语言中另外一个与字符串关系非常密切的类型就是字节(字节)了,相信各位读者也都非常了解,这里也就不展开介绍。
我们在这一节中就会详细介绍这两种基本类型的实现原理以及它们的转换关系,但是这里还是会将介绍的重点主要放在字符串上,因为这是我们接触最多的一种基本类型并且后者就是一个简单的uint8类型,所以会给予字符串最大的篇幅,需要注意的是这篇文章不会使用大量的篇幅介绍UTD-8以及编码等知识,主要关注的还是字符串的结构以及常见操作的实现。
字符串虽然在去语言中是基本类型字符串,但是它其实就是字符组成的数组,C语言中的字符串就可以用char[]来表示,作为数组来说它会占用一片连续的内存空间,这片连续的内存空间就存储了一些字节,这些字节共同组成了字符串,去语言中的字符串是一个只读的字节数组切片、下面就是一个只读的“hello"字符串在内存中的结构:
如果是代码中存在的字符串,会在编译期间被标记成只读数据SRODATA符号,假设我们有以下的一段代码,其中包含了一个字符串,当我们将这段代码编译成汇编语言时,就能够看到你好字符串有一个SRODATA的标记:
,美元cat main.go package 主要 func main (), { ,str :=,“hello" ,println([]字节(str)) } 美元,美好=linux GOARCH=amd64 go tool compile -S main.go … 干净自己的go.string hello" SRODATA dupok 大?5 ,0 x0000 68年,65年,6 c 6 c 6 f ,,,你好 …
不过这只能表明编译期间存在的字符串会被直接分配到只读的内存空间并且这段内存不会被更改,但是在运行时我们其实还是可以将这段内存拷贝到其他的堆或者栈上,同时将变量的类型修改成[]字节在修改之后再通过类型转换变成字符串,不过如果想要直接修改字符串类型变量的内存空间,去语言是不支持这种操作的。
除了今天的主角字符串之外,另外的配角字节也还是需要简单介绍一下的,字节其实非常好理解,每一个字节就是8个,相信稍微对编程有所了解的人应该都对这个概念一清二楚,而字节数组也没什么值得介绍的,所以这里就直接跳过了。
字符串在去语言中的接口其实非常简单,每一个字符串在运行时都会使用如下的StringHeader结构体去表示,在运行时包的内部其实有一个私有的结构StringHeader,它有着完全相同的结构只是用于存储数据的数据字段使用了不安全。指针类型:
type StringHeader struct { Data uintptr Len int }
为什么我们会说字符串其实是一个只读类型的切片呢,我们可以看一下切片在去语言中的运行时表示:
type SliceHeader struct { Data uintptr Len int Cap int }
这个表示切片的结构SliceHeader和字符串的结构StringHeader非常类似,与切片的结构相比,字符串少了一个表示容量的帽字段,这是因为字符串作为只读的类型,我们并不会直接向字符串直接追加元素改变其本身的内存空间,所有追加的操作都是通过拷贝来完成的。
字符串的解析一定是解析器在词法分析时就完成的,词法分析阶段会对源文件中的字符串进行切片和分组,将原有无意义的字符流转换成牌序列,在去语言中,有两种字面量的方式可以声明一个字符串,一种是使用双引号,另一种是使用反引号:
str1 :=,“却;能够is a string" str2 :=, '却;能够is another 字符串的
使用双引号声明的字符串其实和其他语言中的字符串没有太多的区别,它只能用于简单,单行的字符串并且如果字符串内部出现双引号时需要使用\符号避免编译器的解析错误,而反引号声明的字符串就可以摆脱单行的限制,因为双引号不再标记字符串的开始和结束,我们可以在字符串内部直接使用“;,在遇到需要写JSON或者其他数据格式的场景下非常方便。