Pablo Fernandez
Pablo Fernandez

Reputation: 105220

interface{} variable to []interface{}

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?

Upvotes: 3

Views: 168

Answers (3)

icza
icza

Reputation: 417642

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.

Upvotes: 1

Corvus Crypto
Corvus Crypto

Reputation: 2291

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 (
    "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

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.

Upvotes: 0

OneOfOne
OneOfOne

Reputation: 99234

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
}

playground

Upvotes: 1

Related Questions