如何将未知大小的字节片转换为字节数组?

时间:2019-12-22 16:41:39

标签: arrays go slice

我需要解组一些数据,在一种情况下,经过编组的数据代表一个以字节数组为键的映射。

不允许将切片用作映射键,但可以使用数组。但是这里的问题是,据我所知,无法以非恒定大小创建数组。

示例:

package main

import (
    "fmt"
    "reflect"
)

func getHashable(value interface{}) interface{} {
    rfl := reflect.ValueOf(value)
    if rfl.Kind() == reflect.Slice && rfl.Type().Elem().Kind() == reflect.Uint8 {
        slice, ok := value.([]uint8)
        if !ok {
            panic(fmt.Errorf("Could not coerce to []uint8"))
        }
        var arr [len(slice)]uint8 // This fails
        copy(arr, slice)
        value = arr
    }
    return value
}

func unmarshalMap(serialized []byte) map[interface{}]interface{} {
    result := make(map[interface{}]interface{})
    for len(serialized) > 0 {
        var value interface{}
        key, bytesConsumed := deserializeValue(serialized)
        serialized = serialized[bytesConsumed:]
        value, bytesConsumed = deserializeValue(serialized)
        serialized = serialized[bytesConsumed:]
        result[getHashable(key)] = value
    }
}

如果deserializeValue()返回一个[] byte,则不能将其作为键存储在结果图中。数组可以工作,但是我无法创建数组,因为我不知道在运行时需要什么大小,并且它只允许编译时间常数。

简化版本https://play.golang.org/p/wkYGs3S-uSD失败,并显示错误消息

./prog.go:15:12: non-constant array bound len(slice)

在Go语言中,如何使用已解组的字节数组作为键?

2 个答案:

答案 0 :(得分:3)

使用string而不是固定大小的字节数组。字符串可以包含任意字节序列。

func getHashable(value interface{}) interface{} {
    rfl := reflect.ValueOf(value)
    if rfl.Kind() == reflect.Slice && rfl.Type().Elem().Kind() == reflect.Uint8 {
        value = string(rfl.Bytes())
    }
    return value
}

如果只需要处理[]byte而不为[]byte命名,请使用类型断言而不是反射:

func getHashable(value interface{}) interface{} {
    switch value := value.(type) {
    case []byte:
         return string(value)
    default:
         return value
    }
}

如果地图的用户需要将字符串键与从[] byte创建的键中区分出来,请定义一个字符串类型以区分这些值:

type convertedSlice string

在上面的代码中用string()代替convertedSlice()的转换。

应用程序可以使用以下方法检查转换后的密钥:

_, ok := key.(convertedSlice) // ok is true if key is converted slice.

并使用以下命令将密钥转换回[] byte:

cv, ok := key.(convertedSice)
if ok {
   key = []byte(cv)
}

答案 1 :(得分:3)

虽然使用string显然是更好的方法,但是如果您不控制的代码使用字节数组作为键,则可以通过以下方法使用反射将字节片转换为数组作为接口。

varr := reflect.New(reflect.ArrayOf(len(slice), reflect.TypeOf(uint8(0))))
reflect.Copy(varr.Elem(), reflect.ValueOf(slice))

return varr.Elem().Interface()

在使用此功能之前,请考虑其他选项。

游乐场:https://play.golang.org/p/CXsxZwgjiRR