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

我需要填充一个具有 type 成员的结构[8]uint8。这需要用初始化为长度 8 的类型的字节数组填充。[]byte简单的方法不起作用:

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

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

由于这两个数组在结构上是相同的,如果这可以通过转换/赋值而不是复制来完成,那会很好吗?


富国沪深
浏览 395回答 3
3回答

HUWWW

背景您的“简单方法”的问题在于 slice (任何类型)是struct由一个指针和两个整数组成的类型值;指针包含底层(后备)数据数组的地址,整数包含为该切片返回的内容len()和内置函数。cap()换句话说,切片是数组的一种视图。然后,在 Go 中,没有类型转换的概念;只有类型转换,并且这些转换可能只发生在具有相同底层表示的类型之间。由于切片和数组可能不具有相同的底层表示(数组实际上是一个连续的内存块,其大小足以包含所有数组元素),您所谓的类型转换可能不合法。可能的解决方案有两种可能的解决方案。最简单的方法是将数据从切片的支持数组复制到新分配的数组中:var (    src = []byte{1, 2, 3, 4, 5, 6, 7, 8}    dst [8]uint8)copy(dst[:], src[:8])请注意,切片和数组类型之间存在固有差异:数组类型对其元素的类型及其长度(即长度是类型的一部分)进行编码,而切片类型仅对其元素的类型进行编码元素(并且在运行时可以是任意长度)。这意味着您可能需要在进行此类复制之前进行检查,以确保源切片恰好具有 8 个元素,即len(src) == len(dst).这个不变量可能会被其他一些代码强制执行,但我想我会提前警告你:如果src少于 8 个元素,src[:8]表达式将在运行时出现 panic,如果包含更多,那么就会有是否复制的问题只是其中的前 8 个正是所需要的。第二种方法(诚然比较混乱)是重新使用切片的底层数组: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]))在这里,我们刚刚获取了切片底层数组中包含的第一个元素的地址,并执行了“脏”两阶段类型转换,使获得的指针成为类型——即“数组的地址*[8]uint8” 8uint8秒”。注意两个注意事项:结果指针现在指向与原始切片相同的内存块。这意味着现在可以通过切片和我们获得的指针来改变该内存。一旦您决定将数组的数据分配给类型的变量[8]uint8(并将其作为参数传递给该类型的函数参数),您将取消引用该指针(如 with *dstPtr),并且此时 数组的数据将被复制。我特别提到这一点,因为人们经常诉诸像这样的 hack 来精确地将支持阵列从切片中拉出,以试图不复制内存。长话短说复制数据(在假设验证 len(src) == len(dst)不变保持之后)。复制 8 个字节很快(在典型的 64 位 CPU 上,这将是一条MOV指令,最多两条),代码也很简单。只有当你真的需要优化一些关键的热路径时,才使用第二种解决方案。在这种情况下,对解决方案进行广泛注释并注意不要意外取消引用您的指针。¹ 此规则有明显的例外情况:A[]byte可以类型转换为string,反之亦然。Astring可以类型转换为[]rune,反之亦然。Anint是类型可转换的string(但由于 Go 1.15go vet 给出了关于它的警告,并且将来可能会禁止此功能)。

宝慕林4294392

您可以使用 非常简单地将切片的内容复制byte到数组中,如下所示:uint8copypackage mainimport (    "fmt")func main() {    slice := []byte{1, 2, 3, 4, 5, 6, 7, 8}    array := [8]uint8{}    copy(array[:], slice)    fmt.Println(array)}产出[1 2 3 4 5 6 7 8]在操场上试试吧。但请问您为什么要使用数组?通常最好只使用切片,除非你有充分的理由。

翻翻过去那场雪

从 Go 1.17 开始,您可以直接使用类型转换,从切片到数组指针:    a := make([]byte, 8)    b := (*[8]uint8)(a) // b is pointer to [8]uint8您可以取消引用以获得非指针[8]uint8类型。    a := make([]byte, 8)    b := *(*[8]uint8)(a) // b is [8]uint8笔记:与 不同copy,转换方法不会产生额外分配(不是您的分配,也不可能由 分配copy),因为它只是生成一个指向现有后备数组的指针。尽管取消引用数组指针会生成一个副本。如果数组的长度大于切片的长度,则转换会出现混乱a := make([]byte, 5)b := (*[10]byte)(a) // panics指针指向切片的底层数组,因此通过索引可以看到相同的值:    a := []byte{0xa1, 0xa2}    b := (*[2]uint8)(a)    fmt.Printf("%x\n", a[0]) // a1    b[0] = 0xff    fmt.Printf("%x\n", a[0]) // ff您可以将 from 转换byte为uint8,包括从它们派生的类型文字,因为 byte 是uint8 的别名(等同于)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go