英文:
Is it possible to convert arbitrary length slices to arrays in golang?
问题
基本上,我需要禁止重复值的接收数据,这些数据类型各不相同(例如int8(1),然后uint32(1)或big.Int(1)是无效的),可以按照以下方式实现:
var m map[interface{}]bool
func tryAddValue(value interface{}) {
switch v := value.(type) {
// ... 省略其他类型以保持简洁
case *big.Int:
if v.IsUint64() {
value = v.Uint64()
} else if v.IsInt64() {
value = v.Int64()
} else {
bits := v.Bits()
value = [len(bits)]big.Word(bits)
// ^^^ 这段代码无法编译,因为它不是常量
}
}
if m[value] {
panic(fmt.Errorf("value %v already exists", value))
}
m[value] = true
}
由于切片不能作为映射键,对于big.Int,我唯一的其他选择是字符串转换和数组转换,而字符串转换是昂贵的(此代码将在热路径上执行)。
英文:
Essentially, I need to disallow duplicate values for received data of varying types (i.e. int8(1), then uint32(1) or big.Int(1) is invalid), along the lines of:
var m map[interface{}]bool
func tryAddValue(value interface{}) {
switch v := value.(type) {
// ... other types omitted for brevity
case *big.Int:
if v.IsUint64() {
value = v.Uint64()
} else if v.IsInt64() {
value = v.Int64()
} else {
bits := v.Bits()
value = [len(bits)]big.Word(bits)
// ^^^ This doesn't compile because it's not a constant
}
}
if m[value] {
panic(fmt.Errorf("value %v already exists", value))
}
m[value] = true
}
Since slices cannot be map keys, my only other options for big.Int are string conversion and array conversion, and string conversion is expensive (this code will be on a hot path).
答案1
得分: 0
啊,反射来拯救:
bits := v.Bits()
t := reflect.ArrayOf(len(bits), reflect.TypeOf(bits[0]))
arr := reflect.New(t).Elem()
slice := arr.Slice(0, len(bits)).Interface()
copy(slice.([]big.Word), bits)
value = arr.Interface()
只使用整数类型的基本实现 https://go.dev/play/p/vOS4exXRkEt
注意:除非你真的需要一个实际的数组,否则有更快的方法来创建映射键。请参阅注释。
注意2:上述代码没有考虑符号。要包含符号信息,请手动将其编码为第一个字:
bits := v.Bits()
arrLen := len(bits) + 1
t := reflect.ArrayOf(arrLen, reflect.TypeOf(bits[0]))
arr := reflect.New(t).Elem()
slice := arr.Slice(0, arrLen).Interface().([]big.Word)
slice[0] = big.Word(v.Sign())
copy(slice[1:], bits)
value = arr.Interface()
https://go.dev/play/p/lKJQJJSENw7
英文:
Ah, reflect to the rescue:
bits := v.Bits()
t := reflect.ArrayOf(len(bits), reflect.TypeOf(bits[0]))
arr := reflect.New(t).Elem()
slice := arr.Slice(0, len(bits)).Interface()
copy(slice.([]big.Word), bits)
value = arr.Interface()
Basic implementation with only integer types https://go.dev/play/p/vOS4exXRkEt
Note: Unless you actually need an actual array, there are faster ways to make map keys. See the comments.
Note2: The above code doesn't take into account the sign. To include sign info, manually encode it as the first word:
bits := v.Bits()
arrLen := len(bits) + 1
t := reflect.ArrayOf(arrLen, reflect.TypeOf(bits[0]))
arr := reflect.New(t).Elem()
slice := arr.Slice(0, arrLen).Interface().([]big.Word)
slice[0] = big.Word(v.Sign())
copy(slice[1:], bits)
value = arr.Interface()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论