[]byte与string的两种转换方式和底层实现(2)
[]byte与string的两种转换方式和底层实现
//[]byte转string
func b2s(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
//string转[]byte
func s2b(s string) (b []byte) {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh.Data = sh.Data
bh.Cap = sh.Len
bh.Len = sh.Len
return b
}
可以看出利用reflect.SliceHeader(代表一个运行时的切片) 和 unsafe.Pointer进行指针替换。
为什么可以这么做呢?
前面我们在讲string和[]byte类型的时候就提了,因为两者的底层结构的字段相似!
array和str的len是一致的,而唯一不同的就是cap字段,所以他们的内存布局上是对齐的。
分析
我们看下这两种转换方式底层是如何实现的,这些实现代码在标准库中都是有的,下面底层实现的代码来自Go 1.18.6版本。
标准方式底层实现
string转[]byte底层实现
先看string转[]byte的实现,(实现源码在 src/runtime/string.go 中)
const tmpStringBufSize = 32
//长度32的数组
type tmpBuf [tmpStringBufSize]byte
//时间函数
func stringtoslicebyte(buf *tmpBuf, s string) []byte {
var b []byte
//判断字符串长度是否小于等于32
if buf != nil && len(s) <= len(buf) {
*buf = tmpBuf{}
b = buf[:len(s)]
} else {
//预定义数组长度不够,重新分配内存
b = rawbyteslice(len(s))
}
copy(b, s)
return b
}
// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
//rawbyteslice函数 分配一个新的字节片。字节片未归零
func rawbyteslice(size int) (b []byte) {
cap := roundupsize(uintptr(size))
p := mallocgc(cap, nil, false)
if cap != uintptr(size) {
memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
}
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
return
}
![[]byte与string的两种转换方式和底层实现](https://www.itdai.com/uploads/allimg/240325/20242A050-2.jpg)
上面代码可以看出string转[]byte是,会根据字符串长度来决定是否需要重新分配一块内存。
- •预先定义了一个长度为32的数组
- •若字符串的长度不超过这个长度32的数组,copy函数实现string到[]byte的拷贝
- •若字符串的长度超过了这个长度32的数组,重新分配一块内存了,再进行copy
[]byte转string底层实现
再看[]byte转string的实现,(实现源码在 src/runtime/string.go 中)
const tmpStringBufSize = 32
//长度32的数组
type tmpBuf [tmpStringBufSize]byte
//实现函数
func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
...
if n == 1 {
p := unsafe.Pointer(&staticuint64s[*ptr])
if goarch.BigEndian {
p = add(p, 7)
}
stringStructOf(&str).str = p
stringStructOf(&str).len = 1
return
}
var p unsafe.Pointer
//判断字符串长度是否小于等于32
if buf != nil && n <= len(buf) {
p = unsafe.Pointer(buf)
} else {
p = mallocgc(uintptr(n), nil, false)
}
stringStructOf(&str).str = p
stringStructOf(&str).len = n
//拷贝byte数组至字符串
memmove(p, unsafe.Pointer(ptr), uintptr(n))
return
}
相关阅读
-
如何在香港BGP服务器上进行安全性和隐私性配置?
如果想知道如何在香港BGP服务器上进行安全性和隐私性配置方面的知识,如有不对的地方欢迎指正! 香港BGP服务器是在香港运营的,它是基于BGP多线路的网络拓扑所构建的服务器,主要面向于
-
b2c电子商务网站建设方案 大型b2c网站建设规定
IT袋网为大家说一说b2c电子商务网站建设方案和大型b2c网站建设规定方面的内容,具体内容如下: 访客来到你的B2C网站,是因为他们相信你的网站能给他带来有价值的东西,这些信息也是他们
-
如何处理服务器网络连接不稳定? 服务器网络不稳定有哪些原因
全面为您解析如何处理服务器网络连接不稳定的话题,请看下面详细的介绍。 服务器网络连接是通过硬件和软件系统实现的,当它出现连接不稳定的问题时,这其中可能存在有多种原因。 为了
-
租用美国高带宽服务器的重要性有哪些?
跟大家说一说租用美国高带宽服务器的重要性有哪些的相关介绍,一起来看看吧! 租用美国高带宽服务器的重要性?美国是拥有许多互联网资源,在美国IP资源和带宽资源也是非常丰富的。 提到


