关于golang:golang-string转换为byte

golang中将string转换为byte切片,能够应用规范转换方法,也能够通过强转形式。两种形式的后果一样,然而执行效率差异很大。如下是我的两种转化形式,效率比规范的转换高很多。

在贴代码前,先理解一下string和slice的Header定义

StringHeader如下,他是string的底层实现

type StringHeader struct {
   Data uintptr
   Len  int
}

SliceHeader如下

type SliceHeader struct {
   Data uintptr
   Len  int
   Cap  int
}

能够发现这两个十分类似
其实就十分好了解了
Data指向理论内容的数组
Len长度

那么咱们就能够开始如下两种操作

  • 将StringHeader中的Data赋值给SliceHeader的Data
    将StringHeader中的Len赋值给SliceHeader的Len
  • 也能够间接将StringHeader强转成SliceHeader(因为各个fields的长度和程序都是一样的)

上面间接上代码

func string2BytesSlicePlus(str string) []byte {
    bytesSlice := []byte{} //此处定义了一个空切片
    stringData := &(*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data//获得StringHeader的Data地址
    byteSliceData := &(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Data //获得SliceHeader的Data地址
    *byteSliceData = *stringData //将StringHeader.Data的值赋给SliceHeader.Data
    (*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Len = (*(*reflect.StringHeader)(unsafe.Pointer(&str))).Len //设置长度

    return bytesSlice
}

间接强转

func string2BytesSlicePlus2(str string) []byte {
    strSliceHeader := *(*reflect.StringHeader)(unsafe.Pointer(&str))
    byteSlice := *(*[]byte)(unsafe.Pointer(&strSliceHeader))

    return byteSlice
}
const (
    TOTALCNT = 1000000
)

func string2BytesSlicePlus(str string) []byte {
    bytesSlice := []byte{}
    stringData := &(*(*reflect.StringHeader)(unsafe.Pointer(&str))).Data
    byteSliceData := &(*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Data
    *byteSliceData = *stringData
    (*(*reflect.SliceHeader)(unsafe.Pointer(&bytesSlice))).Len = (*(*reflect.StringHeader)(unsafe.Pointer(&str))).Len

    return bytesSlice
}

func string2BytesSlicePlus2(str string) []byte {
    strSliceHeader := *(*reflect.StringHeader)(unsafe.Pointer(&str))
    byteSlice := *(*[]byte)(unsafe.Pointer(&strSliceHeader))

    return byteSlice
}

func normalString2BytesSlice(str string) []byte {
    return []byte(str)
}

func TestStringConvert(t *testing.T) {
    origStr := "String convert test"

    convSlice := string2BytesSlicePlus(origStr)

    byteSlice := []byte(origStr)

    if !bytes.Equal(convSlice, byteSlice) {
        t.Fail()
    }

    convSlice = string2BytesSlicePlus2(origStr)
    if !bytes.Equal(convSlice, byteSlice) {
        t.Fail()
    }
}

//Run go test -bench="." -benchmem to verify efficiency
func Benchmark_NormalConvert(t *testing.B) {
    for count := 0; count < TOTALCNT; count++ {
        str := "This is string to byte slice convert test!!!"
        _ = normalString2BytesSlice(str)
    }
}

func Benchmark_PlusConvert(t *testing.B) {
    for count := 0; count < TOTALCNT; count++ {
        str := "This is string to byte slice convert test!!!"
        _ = string2BytesSlicePlus(str)
    }
}

func Benchmark_PlusConvert2(t *testing.B) {
    for count := 0; count < TOTALCNT; count++ {
        str := "This is string to byte slice convert test!!!"
        _ = string2BytesSlicePlus2(str)
    }
}

执行测试

go test -bench="." -benchmem

测试后果

cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
Benchmark_NormalConvert-12      1000000000               0.03040 ns/op         0 B/op          0 allocs/op
Benchmark_PlusConvert-12        1000000000               0.0002572 ns/op               0 B/op          0 allocs/op
Benchmark_PlusConvert2-12       1000000000               0.0002586 ns/op               0 B/op          0 allocs/op
PASS
ok      jianghu.com/godemo/000Tips/T0018/test   0.315s

依据后果能够看出
应用规范办法[]byte(str)转换的效率最低
应用自定义的两种办法简直无差别,效率要高很多百倍的效率差异

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理