doujianguang5506 2018-10-02 13:38
浏览 2128
已采纳

如何将[] byte转换为[8] uint8

I need to populate a struct that has a member of type [8]uint8. This needs be populated with a byte array of type []byte initialized to length 8. The simplistic approach does not work:

Data:   [8]uint8(RequestFrame(0x180, r)),

gives

cannot convert .. (type []byte) to type [8]uint8

Since both arrays are structurally identical it would be nice if this could be done with casting/assignment rather than copying?

  • 写回答

2条回答 默认 最新

  • doutuo1908 2018-10-02 14:54
    关注

    Background

    The problem with your "simplistic approach" is that a slice (of any type) is a struct-typed consisting of a pointer and two integers; the pointer contains the address of the underlying (backing) data array, and the integers contain what len() and cap() builtins return for that slice.

    In other words, a slice is sort of a view into an array.

    Then, in Go, there is no concept of a type cast; there are only type conversions, and these conversions may only happen between types with the same underlying representation¹.

    Since a slice and an array may not have the same underlying representation (array is literally a contiguous block of memory of the size just enough to contain all the array's elements), your alleged type conversion may not be legal.

    Possible solutions

    There are two possible solutions.

    The simplest is to just copy the data from the slice's backing array into a newly-allocated array:

    var (
        src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
        dst [8]uint8
    )
    copy(dst[:], src[:8])
    

    Note that there exists an inherent disparity between slice an array types: an array type encodes both the type of its elements and its length (that is, the length is a part of the type), while a slice type only encodes the type of its elements (and may be of any length at runtime).

    This means that you might need to have a check before such copying that makes sure the source slice has exactly 8 elements, that is, len(src) == len(dst).

    This invariant may be enforced by some other code, but I think I'd warn you up front about this: if src has less than 8 elements, the src[:8] expression will panic at runtime, and if it contains more, then there's the question of whether copying just the first 8 of them is exactly what's needed.

    The second approach (admittedly messier) is to just re-use the underlying array of the slice:

    import "unsafe"
    
    var (
        src    = []byte{1, 2, 3, 4, 5, 6, 7, 8}
        dstPtr *[8]uint8
    )
    
    if len(src) != len(*dstPtr) {
        panic("boom")
    }
    dstPtr = (*[8]uint8)(unsafe.Pointer(&src[0]))
    

    Here, we've just taken the address of the first element contained in the slice's underlying array and peformed a "dirty" two-phase type-conversion to make the obtained pointer to be of type *[8]uint8—that is, "an address of an array of 8 uint8s".

    Note two caveats:

    • The resulting pointer now points to the same memory block the original slice does. It means it's now possible to mutate that memory both through the slice and the pointer we obtained.

    • As soon as you'll decide to assign the array's data to a variable of type [8]uint8 (and passing it as an argument to a function's parameter of that type), you will dereference that pointer (like with *dstPtr), and at that moment the array's data will be copied.

      I'm specifically mentioning this as often people resort to hacks like this one to pull the backing array out of a slice precisely in an attempt to not copy the memory.

    TL;DR

    Copy the data (after supposedly verifying the len(src) == len(dst) invariant holds).

    Copying 8 bytes is fast (on a typical 64-bit CPU this will be a single MOV instruction, or two at most), and the code will be straightforward.

    Only resort to hacks from the second solution when you really need to optimize on some critical hot path. In that case, comment the solution extensively and watch for not accidentally dereferencing your pointer.


    ¹ There is a single but notable exception to this rule: a []byte is type-convertible to string, and vice-versa.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)