简单谈谈简单谈谈Golang中的字符串与字节数组中的字符串与字节数组
主要给大家介绍了关于Golang中字符串与字节数组的相关资料,文中通过示例代码介绍的非常详细,对大家的
学习或者使用Golang具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
前言前言
字符串是 Go 语言中最常用的基础数据类型之一,虽然字符串往往都被看做是一个整体,但是实际上字符串是一片连续的内存
空间,我们也可以将它理解成一个由字符组成的数组,Go 语言中另外一个与字符串关系非常密切的类型就是字节(Byte)
了,相信各位读者也都非常了解,这里也就不展开介绍。
我们在这一节中就会详细介绍这两种基本类型的实现原理以及它们的转换关系,但是这里还是会将介绍的重点主要放在字符串
上,因为这是我们接触最多的一种基本类型并且后者就是一个简单的 uint8 类型,所以会给予 string 最大的篇幅,需要注意的
是这篇文章不会使用大量的篇幅介绍 UTD-8 以及编码等知识,主要关注的还是字符串的结构以及常见操作的实现。
字符串虽然在 Go 语言中是基本类型 string ,但是它其实就是字符组成的数组,C 语言中的字符串就可以用 char[] 来表示,作
为数组来说它会占用一片连续的内存空间,这片连续的内存空间就存储了一些 字节 ,这些字节共同组成了字符串, Go 语言
中的字符串是一个只读的字节数组切片 ,下面就是一个只读的 "hello" 字符串在内存中的结构:
如果是代码中存在的字符串,会在编译期间被标记成只读数据 SRODATA 符号,假设我们有以下的一段代码,其中包含了一
个字符串,当我们将这段代码编译成汇编语言时,就能够看到 hello 字符串有一个 SRODATA 的标记:
$ cat main.go
package main
func main() {
str := "hello"
println([]byte(str))
}
$ GOOS=linux GOARCH=amd64 go tool compile -S main.go
...
go.string."hello" SRODATA dupok size=5
0x0000 68 65 6c 6c 6f hello
...
不过这只能表明编译期间存在的字符串会被直接分配到只读的内存空间并且这段内存不会被更改,但是在运行时我们其实还是
可以将这段内存拷贝到其他的堆或者栈上,同时将变量的类型修改成 []byte 在修改之后再通过类型转换变成 string ,不过如果
想要直接修改 string 类型变量的内存空间,Go 语言是不支持这种操作的。
除了今天的主角字符串之外,另外的配角 byte 也还是需要简单介绍一下的,byte 其实非常好理解,每一个 byte 就是 8 个
bit,相信稍微对编程有所了解的人应该都对这个概念一清二楚,而字节数组也没什么值得介绍的,所以这里就直接跳过了。
字符串在 Go 语言中的接口其实非常简单,每一个字符串在运行时都会使用如下的 StringHeader 结构体去表示,在运行时包
的内部其实有一个私有的结构 stringHeader ,它有着完全相同的结构只是用于存储数据的 Data 字段使用了 unsafe.Pointer 类
型:
type StringHeader struct {
Data uintptr
Len int
}
为什么我们会说字符串其实是一个只读类型的切片 呢,我们可以看一下切片在 Go 语言中的运行时表示:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
这个表示切片的结构 SliceHeader 和字符串的结构 StringHeader 非常类似,与切片的结构相比,字符串少了一个表示容量的
Cap 字段,这是因为字符串作为只读的类型,我们并不会直接向字符串直接追加元素改变其本身的内存空间,所有追加的操
作都是通过拷贝来完成的。