golang中struct和[]byte的相互转换示例

红粒炊畲粟,青烟郁涧薪。得床思熟睡,寒犬苦狺狺。一生之中至少要有两次冲动,一次为奋不顾身的爱情,一次为说走就走的旅行。

在网络传输过程中,经常会这样处理:socket接收到数据,先获取其消息头,然后再做各种不同的业务处理。在解析消息头的时候的方法有多种多样。其中最为高效解析消息头的方法就是直接把数据头部分强制类型转换为对应的消息头结构体。这种做法在C/C++中非常的常见。而golang其实也是可以这样子做的。类似这样的应用,直接类型转换获取消息对应的解析方法其实效率会相对较高。

golang中struct和[]byte的转换方法,其实就是用到了golang中的unsafe包加上类型转换 , 约束:struct中不能有指针类型。

1、struct转化为[]byte,转换方法如下:

import (
  "fmt"
  "unsafe"
)
type TestStructTobytes struct {
  data int64
}
type SliceMock struct {
  addr uintptr
  len int
  cap int
}

func main() {

  var testStruct = &TestStructTobytes{100}
  Len := unsafe.Sizeof(*testStruct)
  testBytes := &SliceMock{
    addr: uintptr(unsafe.Pointer(testStruct)),
    cap: int(Len),
    len: int(Len),
  }
  data := *(*[]byte)(unsafe.Pointer(testBytes))
  fmt.Println("[]byte is : ", data)
} 

运行结果:

[]byte is : [100 0 0 0 0 0 0 0]

因为[]byte底层的数据结构为:

struct { 
 addr uintptr 
 len int 
 cap int 
 } 

其中addr为数值的地址,len为当地数值的长度,cap为数值的容量。

转换的时候,需要定义一个和[]byte底层结构一致的struct(如例子中的SliceMock),然后把结构体的地址赋给addr,结构体的大小赋给len和cap。最后将其转换为[]byte类型。

2、将[]byte转换为struct,转换方法如下:

import (
  "fmt"
  "unsafe"
)
type TestStructTobytes struct {
  data int64
}
type SliceMock struct {
  addr uintptr
  len int
  cap int
}

func main() {

  var testStruct = &TestStructTobytes{100}
  Len := unsafe.Sizeof(*testStruct)
  testBytes := &SliceMock{
    addr: uintptr(unsafe.Pointer(testStruct)),
    cap: int(Len),
    len: int(Len),
  }
  data := *(*[]byte)(unsafe.Pointer(testBytes))
  fmt.Println("[]byte is : ", data)
  var ptestStruct *TestStructTobytes = *(**TestStructTobytes)(unsafe.Pointer(&data))
  fmt.Println("ptestStruct.data is : ", ptestStruct.data)
} 

运行结果:

[]byte is : [100 0 0 0 0 0 0 0]
ptestStruct.data is : 100

从上面的例子中将[]byte转换为struct的代码片段为:

var ptestStruct *TestStructTobytes = *(**TestStructTobytes)(unsafe.Pointer(&data))

分析:

由于在golang中编译器不将[]byte视为指针,所以要使用其地址进行转换,由于[]byte底层存放的是指向数据的地址。用[]byte的地址就需要使用双层指针转换,然后再指向其内容,得出来的就是转换对应struct的指针了。

本文golang中struct和[]byte的相互转换示例到此结束。命运,是一个很飘渺的东西,有人相信命运,走到了塔顶,或者坠落到崖底。有人想逆天改命,但成功的几率,与中彩一样,但有了毅力,终有那么一天,前方,不再是灰色的雾。小编再次感谢大家对我们的支持!

您可能有感兴趣的文章
golang并发编程的如何实现

golang如何实现redis的延时消息队列功能示例

golang中range在slice和map遍历中的注意事项

Golang命令行进行debug调试操作

golang的空标识符理解