Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if interface{} is a slice

I'm noob in Go :) so my question may be stupid, but can't find answer, so.

I need a function:

func name (v interface{}) {
    if is_slice() {
        for _, i := range v {
            my_var := i.(MyInterface)
            ... do smth
        }
    } else {
        my_var := v.(MyInterface)
        ... do smth
    }
}

How can I do is_slice in Go? Appreciate any help.

like image 971
Alexander Avatar asked Oct 31 '16 13:10

Alexander


3 Answers

The is_slice method can be something like this:

func IsSlice(v interface{}) bool {
    return reflect.TypeOf(v).Kind() == reflect.Slice
}

Can also put additional condition of reflect.TypeOf(v).Kind() == reflect.Array if required.

like image 56
pratpor Avatar answered Nov 18 '22 08:11

pratpor


In your case the type switch is the simplest and most convenient solution:

func name(v interface{}) {
    switch x := v.(type) {
    case []MyInterface:
        fmt.Println("[]MyInterface, len:", len(x))
        for _, i := range x {
            fmt.Println(i)
        }
    case MyInterface:
        fmt.Println("MyInterface:", x)
    default:
        fmt.Printf("Unsupported type: %T\n", x)
    }
}

The case branches enumerate the possible types, and inside them the x variable will already be of that type, so you can use it so.

Testing it:

type MyInterface interface {
    io.Writer
}

var i MyInterface = os.Stdout
name(i)
var s = []MyInterface{i, i}
name(s)
name("something else")

Output (try it on the Go Playground):

MyInterface: &{0x1040e110}
[]MyInterface, len: 2
&{0x1040e110}
&{0x1040e110}
Unsupported type: string

For a single type check you may also use type assertion:

if x, ok := v.([]MyInterface); ok {
    // x is of type []MyInterface
    for _, i := range x {
        fmt.Println(i)
    }
} else {
    // x is not of type []MyInterface or it is nil
}

There are also other ways, using package reflect you can write a more general (and slower) solution, but if you're just starting Go, you shouldn't dig into reflection yet.

like image 29
icza Avatar answered Nov 18 '22 06:11

icza


icza's answer is correct, but is not recommended by go creators:

interface{} says nothing

A better approach may be to define a function for each type you have:

func name(v MyInterface) {
    // do something
}

func names(vs []MyInterface) {
    for _, v := range(vs) {
        name(v)
    }
}
like image 3
Lucas Gabriel Sánchez Avatar answered Nov 18 '22 07:11

Lucas Gabriel Sánchez