亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何將 []byte 轉換為 [8]uint8

如何將 []byte 轉換為 [8]uint8

Go
富國滬深 2023-04-17 15:29:05
我需要填充一個具有 type 成員的結構[8]uint8。這需要用初始化為長度 8 的類型的字節數組填充。[]byte簡單的方法不起作用:Data:   [8]uint8(RequestFrame(0x180, r)),給cannot convert .. (type []byte) to type [8]uint8由于這兩個數組在結構上是相同的,如果這可以通過轉換/賦值而不是復制來完成,那會很好嗎?
查看完整描述

3 回答

?
HUWWW

TA貢獻1874條經驗 獲得超12個贊

背景

您的“簡單方法”的問題在于 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指令,最多兩條),代碼也很簡單。


只有當你真的需要優化一些關鍵的熱路徑時,才使用第二種解決方案。在這種情況下,對解決方案進行廣泛注釋并注意不要意外取消引用您的指針。


1 此規則有明顯的例外情況:


A[]byte可以類型轉換為string,反之亦然。

Astring可以類型轉換為[]rune,反之亦然。

Anint是類型可轉換的string(但由于 Go 1.15go vet 給出了關于它的警告,并且將來可能會禁止此功能)。



查看完整回答
反對 回復 2023-04-17
?
寶慕林4294392

TA貢獻2021條經驗 獲得超8個贊

您可以使用 非常簡單地將切片的內容復制byte到數組中,如下所示:uint8copy


package main


import (

    "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]

在操場上試試吧。


但請問您為什么要使用數組?通常最好只使用切片,除非你有充分的理由。


查看完整回答
反對 回復 2023-04-17
?
翻翻過去那場雪

TA貢獻2065條經驗 獲得超14個贊

從 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 的別名(等同于)。


查看完整回答
反對 回復 2023-04-17
  • 3 回答
  • 0 關注
  • 489 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號