Home > database >  How to check if interface is a a pointer to a slice
How to check if interface is a a pointer to a slice

Time:10-23

I know how to check if an interface is a pointer:

func isPointerArray(i interface{}) bool {
    if i == nil {
        return false
    }
    if reflect.ValueOf(i).Kind() != reflect.Ptr {
        return false
    }
}

But how can I check if that pointer is a slice? TypeOf is a pointer.

CodePudding user response:

If the value's kind is reflect.Ptr, you may use Value.Elem() to get the pointed value, and you may compare its kind to reflect.Slice.

This is how it would look like:

func isPtrSlice(i interface{}) bool {
    if i == nil {
        return false
    }
    v := reflect.ValueOf(i)
    if v.Kind() != reflect.Ptr {
        return false
    }
    return v.Elem().Kind() == reflect.Slice
}

But there's one catch though. If the value passed is a pointer to slice type but the value itself is the nil pointer, this will report false. Understandable, as there is no pointed value whose type could be a slice. This may or may not be what you want.

If you want true even for nil pointer values (that are of pointer to slice types), you may use reflect.Type instead of reflect.Value. This works for nil pointers too, because even though there is no pointed value, there is still a pointed type (called the base type).

func isPtrSlice2(i interface{}) bool {
    if i == nil {
        return false
    }
    t := reflect.TypeOf(i)
    if t.Kind() != reflect.Ptr {
        return false
    }
    return t.Elem().Kind() == reflect.Slice
}

Testing the above functions:

vals := []interface{}{
    nil,
    "a",
    &image.Point{},
    []string{},
    &[]string{},
    (*[]string)(nil),
}

for _, v := range vals {
    fmt.Printf("%-14T isPtrSlice: %-5t, isPtrSlice2: %t\n",
        v, isPtrSlice(v), isPtrSlice2(v))
}

Which will output (try it on the Go Playground):

<nil>          isPtrSlice: false, isPtrSlice2: false
string         isPtrSlice: false, isPtrSlice2: false
*image.Point   isPtrSlice: false, isPtrSlice2: false
[]string       isPtrSlice: false, isPtrSlice2: false
*[]string      isPtrSlice: true , isPtrSlice2: true
*[]string      isPtrSlice: false, isPtrSlice2: true

As you can see in the last line (where the value is a nil pointer of type *[]string) isPtrSlice() returns false while isPtrSlice2() returns true.

CodePudding user response:

You can use type assertions:

package main

import "fmt"

func main() {
    var value interface{}
    value = &[]int{1, 2}

    if res, ok := value.(*[]int); ok {
        fmt.Println(res)
    }
}
  • Related