string类型和[]byte类型是我们编程时最常使用到的数据结构。本文将探讨两者之间的转换方式,通过分析它们之间的内在联系来拨开迷雾。

两种转换方式

  • 标准转换

go中string与[]byte的互换,相信每一位gopher都能立刻想到以下的转换方式,我们将之称为标准转换。

// string to []byte
    s1 := "hello"
    b := []byte(s1)

    // []byte to string
    s2 := string(b)
  • 强转换

通过unsafe和reflect包,可以实现另外一种转换方式,我们将之称为强转换(也常常被人称作黑魔法)。

func String2Bytes(s string) []byte {
    
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    bh := reflect.SliceHeader{
    
        Data: sh.Data,
        Len:  sh.Len,
        Cap:  sh.Len,
    }
    return *(*[]byte)(unsafe.Pointer(&bh))
}

func Bytes2String(b []byte) string {
    
    return *(*string)(unsafe.Pointer(&b))
}
  • 性能对比

既然有两种转换方式,那么我们有必要对它们做性能对比。

// 测试强转换功能
func TestBytes2String(t *testing.T) {
    
    x := []byte("Hello Gopher!")
    y := Bytes2String(x)
    z := string(x)

    if y != z {
    
        t.Fail()
    }
}

// 测试强转换功能
func TestString2Bytes(t *testing.T) {
    
    x := "Hello Gopher!"
    y := String2Bytes(x)
    z := []byte(x)

    if !bytes.Equal(y, z) {
    
        t.Fail()
    }
}

// 测试标准转换string()性能
func Benchmark_NormalBytes2String(b *testing.B) {
    
    x := []byte("Hello Gopher! Hello Gopher! Hello Gopher!")
    for i := 0; i < b.N; i++ {
    
        _ = string(x)
    }
}

// 测试强转换[]byte到string性能
func Benchmark_Byte2String(b *testing.B) {
    
    x := []byte("Hello Gopher! Hello Gopher! Hello Gopher!")
    for i := 0; i < b.N; i++ {
    
        _ = Bytes2String(x)
    }
}

// 测试标准转换[]byte性能
func Benchmark_NormalString2Bytes(b *testing.B) {
    
    x := "Hello Gopher! Hello Gopher! Hello Gopher!"
    for i := 0; i < b.N; i++ {
    
        _ = []byte(x)
    }
}

// 测试强转换string到[]byte性能
func Benchmark_String2Bytes(b *testing.B) {
    
    x := "Hello Gopher! Hello Gopher! Hello Gopher!"
    for i := 0; i < b.N; i++ {
    
        _ = String2Bytes(x)
    }
}

测试结果如下

$ go test -bench="." -benchmem
goos: darwin
goarch: amd64
pkg: workspace/example/stringBytes
Benchmark_NormalBytes2String-8          38363413                27.9 ns/op            48 B/op          1 allocs/op
Benchmark_Byte2String-8                 1000000000               0.265 ns/op           0 B/op          0 allocs/op
Benchmark_NormalString2Bytes-8          32577080                34.8 ns/op            48 B/op          1 allocs/op
Benchmark_Stri