How to convert interface{} that's really a slice of types whose kind is reflect.Int32 into slice of int32?

huangapple go评论78阅读模式
英文:

How to convert interface{} that's really a slice of types whose kind is reflect.Int32 into slice of int32?

问题

我有以下代码:

type Int32A int32
type Int32B int32

我想实现一个函数,可以接受任何类型为reflect.Int32的切片,并将其转换为[]int32。例如:

func ConvertTypeSliceToInt32Slice(es interface{}) []int32 {
  result := make([]int32, len(es))
  for i := 0; i < len(result); i++ {
    result[i] = es[i].(int32)
  }

  return result
}

func caller() {
  Int32as := Int32A{1, 2}
  Int32bs := Int32B{3, 5}

  int32as := ConvertTypeSliceToInt32Slice(Int32as)
  int32bs := ConvertTypeSliceToInt32Slice(Int32bs)
}

如何为任意类型定义实现这个功能,其类型为reflect.Int32?(背景:此函数将用于转换proto枚举的切片;即完整的类型集是未知且无限的,因此对每个类型执行switch操作是不可行的)。

另外,我使用的是1.17版本,所以无法使用参数化类型(也称为模板)。

以下是一个不起作用的尝试(在is.([]interface{})处发生恐慌):

func ConvertTypeSliceToInt32Slice(is interface{}) []int32 {
	es := is.([]interface{})
	result := make([]int32, len(es))
	for i := 0; i < len(result); i++ {
		result[i] = es[i].(int32)
	}

	return result
}
英文:

I have the following:

type Int32A int32
type Int32B int32

and would like to implement a function that can accept any slice of types whose kind is reflect.Int32 and convert it into []int32. For example:

func ConvertTypeSliceToInt32Slice(es &#171;es-type&#187;) []int32 {
  result := make([]int32, len(es))
  for i := 0; i &lt; len(result); i++ {
    result[i] = es[i].(int32)
  }

  return result
}

func caller() {
  Int32as := Int32A{1, 2}
  Int32bs := Int32B{3, 5}

  int32as := ConvertTypeSliceToInt32Slice(Int32as)
  int32bs := ConvertTypeSliceToInt32Slice(Int32bs)
}

How can this be done far any arbitrary type definition whose kind is reflect.Int32? (Context: this function will be used to convert slices of proto enums; ie the full set of types is unknown and unbounded so performing a switch on each type isn't feasible).

Also, I'm using 1.17 so I can't use parameterized types (aka templates).

One attempt that doesn't work (it panics at is.([]interface{})):

func ConvertTypeSliceToInt32Slice(is interface{}) []int32 {
	es := is.([]interface{})
	result := make([]int32, len(es))
	for i := 0; i &lt; len(result); i++ {
		result[i] = es[i].(int32)
	}

	return result
}

答案1

得分: 3

在这种情况下,int32是一个"底层类型",而在type parameter declaration中,~是用来指定底层类型的约束条件的方式。

例如:https://go.dev/play/p/8-WAu9KlXl5

func ConvertTypeSliceToInt32Slice[T ~int32](es []T) []int32 {
	result := make([]int32, len(es))
	for i := 0; i < len(result); i++ {
		result[i] = int32(es[i])
	}

	return result
}

如果你需要使用反射,你可以在追加到最终切片之前将每个元素的类型转换为所需类型:

func ConvertTypeSliceToInt32Slice(es interface{}) []int32 {
	v := reflect.ValueOf(es)
	int32ty := reflect.TypeOf(int32(0))

	result := make([]int32, v.Len())
	for i := 0; i < v.Len(); i++ {
		result[i] = v.Index(i).Convert(int32ty).Interface().(int32)
	}
	return result
}

如果你需要确保其他可转换的数值类型不被转换,你可以比较元素类型并根据需要引发 panic 或错误:

if v.Type().Elem().Kind() != reflect.Int32 {
...
英文:

int32 in this case is an "underlying type", and ~ in a type parameter declaration is how you specify a constraint to an underlying type.

For example: https://go.dev/play/p/8-WAu9KlXl5

func ConvertTypeSliceToInt32Slice[T ~int32](es []T) []int32 {
	result := make([]int32, len(es))
	for i := 0; i &lt; len(result); i++ {
		result[i] = int32(es[i])
	}

	return result
}

If you need to use reflection, you can convert the type of each element before appending to the final slice:

func ConvertTypeSliceToInt32Slice(es interface{}) []int32 {
	v := reflect.ValueOf(es)
	int32ty := reflect.TypeOf(int32(0))

	result := make([]int32, v.Len())
	for i := 0; i &lt; v.Len(); i++ {
		result[i] = v.Index(i).Convert(int32ty).Interface().(int32)
	}
	return result
}

And if you need to ensure other convertible numeric types are not converted, you can compare the element type and panic or error as necessary:

if v.Type().Elem().Kind() != reflect.Int32 {
...

huangapple
  • 本文由 发表于 2022年4月15日 00:39:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/71874987.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定