-2

When checking the reflect.Kind() of a slice, reflect correctly identifies it as a slice when not stored inside a pointer:

package main

import (
    "fmt"
    "reflect"
)

type Dog struct {
    Name string
    Age  int
}

func main() {
    var dogs []Dog
    rDogs := reflect.ValueOf(dogs)
    fmt.Println(rDogs.Kind())
}

Output:

slice

However, when a slice is stored inside a pointer, reflect.Kind() identifies it as a struct:

package main

import (
    "fmt"
    "reflect"
)

type Dog struct {
    Name string
    Age  int
}

func main() {
    dogs1 := make([]Dog, 0)
    pointer := &dogs1
    printPointerValueKind(pointer)        

    var dogs2 []Dog
    pointer = &dogs2
    printPointerValueKind(pointer)
}

func printPointerValueKind(pointer interface{}) {
    if pointer != nil {
        rPointer := reflect.ValueOf(pointer)

        if rPointer.Kind() == reflect.Ptr {
            value := rPointer.Elem()
            rValue := reflect.ValueOf(value)
            fmt.Println(rValue.Kind())
        }
    }
}       

Output:

struct
struct

My questions are:

  1. Why does this happen?

  2. Is there a way to store a slice inside a pointer and still have reflect.Kind() identify it as a slice?

Floating Sunfish
  • 4,920
  • 5
  • 29
  • 48
  • @mkopriva I see, so that answers #1. Is #2 even possible then? – Floating Sunfish Dec 05 '19 at 06:44
  • @mkopriva Thank you! That answers my questions! Could you please add this as an answer so I can accept it? – Floating Sunfish Dec 05 '19 at 06:46
  • I think that you have once again gotten the right answer to the wrong question. See https://godoc.org/github.com/jmoiron/sqlx#Select which says that `dest` must "be a slice": you should be writing `var dogs1 []Dog` and then calling `Select` with `&dogs1`, and `Select` will fill in `Dogs1`. You're doing a lot of unnecessary work... – torek Dec 05 '19 at 07:35
  • (BTW if I'm right, this is a classic example of the [XY problem](http://meta.stackexchange.com/a/66378/166789).) – torek Dec 05 '19 at 07:42
  • @torek Yup, `Select()` works with slices and even structs, but we want to enforce on our project that we will only be working with slices, specifically ones that have been initialized with `make()`. – Floating Sunfish Dec 05 '19 at 08:17
  • Note that you can't detect whether a slice was initialized with `make` or just by initializing it: `var s = []T{}` is a non-nil slice `s` pointing to an underlying array with size 0, so it looks just like `var s []T` followed by `s = make([]T)`. – torek Dec 05 '19 at 08:53
  • @torek No worries, we only care about non-nil slices. That was the term I meant to use. – Floating Sunfish Dec 05 '19 at 13:27

1 Answers1

2

1. (reflect.Value).Elem() returns a reflect.Value, which is a struct, and which does not need to be passed to reflect.ValueOf again if you're looking for the kind of the type that the value holds.

2. rPointer.Elem().Kind() should be enough for what you need.

mkopriva
  • 35,176
  • 4
  • 57
  • 71