接口切片的类型转换

接口切片的类型转换

问题描述:

I'm curious why Go does't implicitly convert []T to []interface{} when it will implicitly convert T to interface{}. Is there something non-trivial about this conversion that I'm missing?

Example:

func foo([]interface{}) { /* do something */ }

func main() {
    var a []string = []string{"hello", "world"}
    foo(a)
}

go build complains

cannot use a (type []string) as type []interface {} in function argument

And if I try to do it explicitly, same thing: b := []interface{}(a) complains

cannot convert a (type []string) to type []interface {}

So every time I need to do this conversion (which seems to come up a lot), I've been doing something like this:

b = make([]interface{}, len(a), len(a))
for i := range a {
    b[i] = a[i]
}

Is there a better way to do this, or standard library functions to help with these conversions? It seems kind of silly to write 4 extra lines of code every time I want to call a function that can take a list of e.g. ints or strings.

我很好奇为什么Go不会将 [] T code>隐式转换为 [] interface {} code>时,它将把 T code>隐式转换为 interface {} code>。 我缺少这种转换的重要内容吗? p>

示例: p>

  func foo([] interface {}){/ *做某事* /} 
 
func main(  ){
 var a [] string = [] string {“ hello”,“ world”} 
 foo(a)
} 
  code>  pre> 
 
 

进行构建 code>抱怨 p>

不能在函数参数中使用([string]类型作为[] interface {}类型 p>

如果我尝试显式地执行此操作,则相同: b:= [] interface {}(a) code>抱怨 p>

无法将(类型[]字符串)转换为类型[] interface {} p> blockquote>

所以每次我都需要执行此转换( 似乎很多),我一直在做这样的事情: p>

  b = make([] interface {},len(a),len(a  ))
对于i:=范围a {
b [i] = a [i] 
} 
  code>  pre> 
 
 

是否有更好的方法,或者 标准库函数来帮助进行这些转换? 每次我想调用一个可以列出例如以下内容的函数时,多写4行代码似乎有点愚蠢。 整数或字符串。 p> div>

In Go, there is a general rule that syntax should not hide complex/costly operations. Converting a string to an interface{} is done in O(1) time. Converting a []string to an interface{} is also done in O(1) time since a slice is still one value. However, converting a []string to an []interface{} is O(n) time because each element of the slice must be converted to an interface{}.

The one exception to this rule is converting strings. When converting a string to and from a []byte or a []rune, Go does O(n) work even though conversions are "syntax".

There is no standard library function that will do this conversion for you. You could make one with reflect, but it would be slower than the three line option.

Example with reflection:

func InterfaceSlice(slice interface{}) []interface{} {
    s := reflect.ValueOf(slice)
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    ret := make([]interface{}, s.Len())

    for i:=0; i<s.Len(); i++ {
        ret[i] = s.Index(i).Interface()
    }

    return ret
}

Your best option though is just to use the lines of code you gave in your question:

b := make([]interface{}, len(a))
for i := range a {
    b[i] = a[i]
}

Try interface{} instead. To cast back as slice, try

func foo(bar interface{}) {
    s := bar.([]string)
    // ...
}

The thing you are missing is that T and interface{} which holds a value of T have different representations in memory so can't be trivially converted.

A variable of type T is just its value in memory. There is no associated type information (in Go every variable has a single type known at compile time not at run time). It is represented in memory like this:

  • value

An interface{} holding a variable of type T is represented in memory like this

  • pointer to type T
  • value

So coming back to your original question: why go does't implicitly convert []T to []interface{}?

Converting []T to []interface{} would involve creating a new slice of interface {} values which is a non-trivial operation since the in-memory layout is completely different.

Here is the official explanation: https://github.com/golang/go/wiki/InterfaceSlice

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}

Convert interface{} into any type.

Syntax:

result := interface.(datatype)

Example:

var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string)   //result type is []string.