Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 如何将大小未知的字节片转换为字节数组?_Arrays_Go_Slice - Fatal编程技术网

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

Arrays 如何将大小未知的字节片转换为字节数组?,arrays,go,slice,Arrays,Go,Slice,我需要解组一些数据,在一种情况下,封送的数据表示一个以字节数组作为键的映射 切片不允许作为贴图键,但数组是。但这里的问题是,据我所知,数组不能以非常量大小创建 例如: package main import ( "fmt" "reflect" ) func getHashable(value interface{}) interface{} { rfl := reflect.ValueOf(value) if rfl.Kind() == reflect.Sli

我需要解组一些数据,在一种情况下,封送的数据表示一个以字节数组作为键的映射

切片不允许作为贴图键,但数组是。但这里的问题是,据我所知,数组不能以非常量大小创建

例如:

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
    }
}
如果反序列化值返回[]字节,则不能将其作为键存储在结果映射中。数组可以工作,但我不能创建数组,因为在运行时之前我不知道需要什么大小,而且它只允许编译时常量

简化版本失败并出现错误

./prog.go:15:12: non-constant array bound len(slice)
如何使用已解组的字节数组作为Go映射中的键?

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

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
}
如果您只需要处理[]字节而不需要处理[]字节的命名类型,请使用类型断言而不是反射:

func getHashable(value interface{}) interface{} {
    switch value := value.(type) {
    case []byte:
         return string(value)
    default:
         return value
    }
}
如果映射的用户需要区分字符串键和从[]字节创建的键,请定义字符串类型以区分这些值:

type convertedSlice string
用convertedSlice替换上面代码中字符串转换的使用

应用程序可以通过以下方式检查已转换的密钥:

_, ok := key.(convertedSlice) // ok is true if key is converted slice.
并使用以下命令将键转换回[]字节:

cv, ok := key.(convertedSice)
if ok {
   key = []byte(cv)
}
虽然使用字符串显然是更好的方法,但如果您不控制的代码使用字节数组作为键,下面介绍如何使用reflect将字节片转换为数组作为接口

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

return varr.Elem().Interface()

使用此选项之前请考虑其他选项。


游乐场:

但是map键是一个字节数组,这个库的用户在得到结果时需要知道它是一个字节数组。盲目地将字节数组转换为字符串将产生无效字符。您的要求不清楚。如果您有一个文本字节数组,只需将其用作密钥。如果你有其他听起来像的东西,那么你无论如何都不能保留原始类型,所以这看起来不像是丢失。我正在编写一个解组器,需要将解组的数据传递回用户。如果封送的数据是{[0x81,0xff,0x41,0x11]=true},那么我需要取消封送的结果也在相同的结构中。在这种情况下,字节数组[81 ff 41 11]需要是我从解组函数返回的映射中的键。您是将其解组为标准格式,还是创建自己的格式?无论如何,我不相信这些键可以使用标准Go类型表示。你需要想出一个创造性的解决办法。或者如果你控制了格式,也许你可以想出一个更友好的格式。这不会保留类型。解组字节数组需要生成实际的字节数组,而不是字符串。@Karl从注释中不清楚值与解组的关系。编辑问题以显示解包场景。哦,哇,这是一个美丽的怪物!好的,如果这是唯一可以解组结果为字节数组的映射键的方法,那么我必须考虑是否只说unsupported…注意,根本问题是映射键必须实现==/!=。数组有,但数组的编译时大小是固定的。这个美丽的怪物我喜欢这个词!为您提供一个接口对象,该对象实现相等比较,以及运行时创建的、运行时支持的伪数组,这些伪数组在执行反射代码时作为数组读回,因此从这个意义上说,它们是不存在编译时的数组,所以从这个意义上说,它们不是数组。@torek您完全正确。但我想补充的是,虽然这是尴尬的使用用户可能有一个硬编码数组作为一个关键,但它不太可能射击自己的脚使用时。它不是不安全的,只是坏代码。