将`interface{}`变量转换为`[]interface{}`。

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

interface{} variable to []interface{}

问题

我有一个interface{}变量,我知道它是一个指向切片的指针:

func isPointerToSlice(val interface{}) bool {
    value := reflect.ValueOf(val)
    return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}

但是我发现很难将其强制转换为[]interface{}变量:

if isPointerToSlice(val) {
    slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
    // 'worked' 是 false :(
}

这样不起作用。有什么办法可以解决这个问题吗?

英文:

I have an interface{} variable and I know it's a pointer to slice:

func isPointerToSlice(val interface{}) bool {
	value := reflect.ValueOf(val)
	return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}

But I'm finding difficult to type cast it into an []interface{} variable:

if isPointerToSlice(val) {
  slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
  // 'worked' is false :(
}

This doesn't work. Any idea how can I solve this?

答案1

得分: 1

你可以简单地使用类型断言来获取接口中存储的值,例如:

if isPointerToSlice(val) {
    var result []interface{}
    result = *val.(*[]interface{})
    fmt.Println(result)
} else {
    fmt.Println("Not *[]interface{}")
}

你声称接口中存储的值的类型是指向[]interface{}的指针,即*[]interface{}。类型断言的结果将是一个指针,只需解引用它即可获得切片[]interface{}

使用短变量声明:

result := *val.(*[]interface{}) // result的类型是[]interface{}

Go Playground上尝试一下。

此外,你的尝试也是有效的:

slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)

这里有一个编辑过的 Playground 示例,证明了你的解决方案是可行的。

但是使用反射是不必要的(因为可以使用类型断言来完成)。

还要注意,*[]interface{}*[]someOtherType是两种不同的类型,如果val中有其他类型的值,你将无法获取*[]interface{}的值。

英文:

You can simply use type assertion to obtain the value stored in an interface, e.g.

if isPointerToSlice(val) {
	var result []interface{}
	result = *val.(*[]interface{})
	fmt.Println(result)
} else {
	fmt.Println("Not *[]interface{}")
}

The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.

Using short variable declaration:

result := *val.(*[]interface{}) // type of result is []interface{}

Try it on the Go Playground.


Also your attempt also works:

slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)

Here's the edited the Playground example which proves your solution works.

But using reflection is unnecessary (as it can be done with type assertion).

Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.

答案2

得分: 1

如果你只想将一个切片转换为[]interface{},你可以使用类似以下的代码:

func sliceToIfaceSlice(val interface{}) []interface{} {
    rf := reflect.Indirect(reflect.ValueOf(val)) // 跳过指针
    if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
        // panic("expected a slice or array")
        return nil
    }
    out := make([]interface{}, rf.Len())
    for i := range out {
        out[i] = rf.Index(i).Interface()
    }
    return out
}

playground

英文:

If you just want to convert a slice to []interface{} you can use something like this:

func sliceToIfaceSlice(val interface{}) []interface{} {
	rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
	if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
		// panic("expected a slice or array")
		return nil
	}
	out := make([]interface{}, rf.Len())
	for i := range out {
		out[i] = rf.Index(i).Interface()
	}
	return out
}

<kbd>playground</kbd>

答案3

得分: 0

Icza的答案很好,尤其是当你不能确定你得到的是一个接口切片时,它将起作用。然而,如果你不想完全依赖反射包,并且希望保持导入的代码量较低,你可以使用类型切换来实现相同的功能,只使用内置方法。

使用这种方法,你可以将代码简化为:

package main

import (
	"fmt"
)

func main() {
	s := []interface{}{"one", 2}
	p := &s

	do(p)
}

func do(val interface{}) {
	switch val.(type){
	case *[]interface{}:
		var result []interface{}
		result = *val.(*[]interface{})
		fmt.Println(result)
	}
}

Playground: http://play.golang.org/p/DT_hb8JcVt

缺点是,如果事先不知道切片的确切类型,除非列出所有可能的处理和断言类型,否则这种方法将无法工作。

英文:

Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.

Using this method, you can shorten your code to just:

package main

import (
	&quot;fmt&quot;
)

func main() {
	s := []interface{}{&quot;one&quot;, 2}
	p := &amp;s

	do(p)
}

func do(val interface{}) {
	switch val.(type){
	case *[]interface{}:
		var result []interface{}
		result = *val.(*[]interface{})
		fmt.Println(result)
	}
}

Playground: http://play.golang.org/p/DT_hb8JcVt

The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

huangapple
  • 本文由 发表于 2016年2月11日 00:16:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/35320357.html
匿名

发表评论

匿名网友

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

确定