我们都知道byte切片转字符串用 string(byte[]{'a'}) 就可以办到,但这种方式会在内存中声明一块新的内存来存储字符串,原来的切片在没用被引用的情况下可能会在下一次GC被回收。这里我们可以用unsafe包来达到不申请新内存用原来切片的底层数据来完成切片到字符串的转换。(在go中字符串的底层就是是byte切片,而切片的底层是数组)
下面看代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main import ( "fmt" "unsafe" ) func main() {
b := []byte{'a','b','c'} fmt.Printf("%p\n",&b) s := string(b) fmt.Printf("方式1: %p=>%s\n",&s,s)
s2 := (*string)(unsafe.Pointer(&b)) fmt.Printf("方式2: %p=>%s\n",s2,*s2)
}
|
- 上面代码的执行结果如下:

可以看到用unsafe包的方式转换的变量地址和原始切片的地址是一样的,unsafe包达到了byte切片转 字符串的目的,而且避免了产生新的内存申请。这在需要大量处理byte切片转为字符串的应用场景中可以有很好的作用。比如消息队列,大量减少小内存的申请减少GC的回收压力,对高并发的应用有一定程度的优化作用。
并且两种转换方式的效率也不一样,通过指针的方式更高效,在对性能有着极致要求的时候还是有用,看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package main
import ( "fmt" "time" )
type B struct { b string }
func main() { println(time.Now().AddDate(100, 0,0 ).UnixNano() / 1e6)
f := []byte{'a'} now := time.Now().UnixNano() b := B{} i := 0 for { if i > 100000000 { break } b.b = string(f) i++ } fmt.Println(time.Now().UnixNano()-now)
}
|