go语言string转byte数组 Go底层之string和[]byte相互转换
目录
- 背景
- Go版本
- 源码解释
- 1string转[]byte
- 2[]byte转string
- 拓展资料
背景
在写go代码的经过中,我们会经常遇到字节数组([]byte)和字符串(string)的转换,比如将[]byte转换为string:string(b);
将string转换为[]byte:[]byte(s),这种转换并不是无损耗的,在数据量大的时候会在堆上申请一块新的内存去存储转换之后的数据,要对性能有要求的情况下就要考虑避免这种转换,接下来我们来看一下源码实现。
Go版本
$ go versiongo version go1.21.4 windows/386
源码解释
1string转[]byte
[]byte(s)这种转换方式实际上用了标准库中的stringtoslicebyte函数,文件路径:src/runtime/string.go
func stringtoslicebyte(buf tmpBuf, s string) []byte var b []byte //定义一个字节数组 if buf != nil && len(s) <= len(buf) //临时buf足够就使用临时buf作为返回的字节数组 buf = tmpBuf} b = buf[:len(s)] } else //临时buf不够就申请一块空间作为返回的字节数组 b = rawbyteslice(len(s)) } copy(b, s) //将字符串底层数组的内容拷贝到字节数组中 return b //返回字节数组}
这种转换方式将字符串底层数组的内容拷贝到另一块空间再返回,由于使用了新的空间地址并且涉及到了拷贝,是有一定性能损耗的。
也有技巧直接将字符串的底层数组作为字节数组返回,不使用额外的内存空间和拷贝,然而这个操作比较危险,一旦修改字节数组的内容就会影响到字符串底层数组的内容,而字符串是不允许修改的。
2[]byte转string
string(b)这种转换方式用了标准库中的slicebytetostring函数,文件路径:src/runtime/string.go
func slicebytetostring(buf tmpBuf, ptr byte, n int) string if n == 0 //字节长度为0时,返回空字符串 return “” } if n == 1 //字节长度为1时 p := unsafe.Pointer(&staticuint64s[ptr]) //得到指向字节数组地址对应的int64的值 if goarch.BigEndian //是否为大端字节序 p = add(p, 7) //指针后移7字节 } return unsafe.String((byte)(p), 1) //返回单字节字符串 } var p unsafe.Pointer if buf != nil && n <= len(buf) //字节数组长度小于临时buf长度直接使用临时buf作为字符串底层数组 p = unsafe.Pointer(buf) } else //字节数组长度大于临时buf长度在堆上新申请一块空间 p = mallocgc(uintptr(n), nil, false) } memmove(p, unsafe.Pointer(ptr), uintptr(n)) //将字节数组内容拷贝到新的地址p上 return unsafe.String((byte)(p), n) //转换为string类型返回}
这种转换方式将字节数组的内容拷贝到一个新的地址上做为字符串的底层数组,由于涉及到新的地址空间的申请和拷贝,因此是有一定开销的。
标准库也提供了直接将要转换的字节数组作为字符串底层数组的技巧,slicebytetostringtmp:
func slicebytetostringtmp(ptr byte, n int) string if raceenabled && n > 0 racereadrangepc(unsafe.Pointer(ptr), uintptr(n), getcallerpc(), abi.FuncPCABIInternal(slicebytetostringtmp)) } if msanenabled && n > 0 msanread(unsafe.Pointer(ptr), uintptr(n)) } if asanenabled && n > 0 asanread(unsafe.Pointer(ptr), uintptr(n)) } return unsafe.String(ptr, n) //直接使用要转换的字节数组作为底层数组}
同样如果修改了字节数组的内容,字符串也会被影响,不推荐使用。
拓展资料
字符串和字节数组转换虽然很简单,然而会带来一定的开销,当然并不是就不能使用这种转换方式,最主要还是根据我们的业务场景去使用,大部分业务场景性能要求并不是在这,然而我们也要尽量避免频繁的进行字符串和字节数组的相互转换。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。
无论兄弟们可能感兴趣的文章:
- go语言中的Stringer的使用示例详解
- Go中strings包的基本使用示例代码
- Go语言字符串处理库strings包详解
- Go语言中strings.HasPrefix、strings.Split、strings.SplitN()?函数
- go中string、int、float相互转换方式