11
votes

This playground illustrates my question.

Basically I have a function that accepts an empty interface as argument. I want to pass anything in and print information on the types and values.

It works as expected except when I pass a pointer to a custom type (in my example, of underlying struct type). I am not entirely sure how the reflection model is structured at that point. Since the function signature specifies an interface{} argument when I call reflect.Indirect(v).Kind() it naturally returns interface but I want to know the type when the function is called.

Below is the same code from playground:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var s interface{}
    s = CustomStruct{}

    PrintReflectionInfo(s)
    PrintReflectionInfo(&s)
}

type CustomStruct struct {}

func PrintReflectionInfo(v interface{}) {
    // expect CustomStruct if non pointer
    fmt.Println("Actual type is:", reflect.TypeOf(v))

    // expect struct if non pointer
    fmt.Println("Value type is:", reflect.ValueOf(v).Kind())

    if reflect.ValueOf(v).Kind() == reflect.Ptr {
        // expect: CustomStruct
        fmt.Println("Indirect type is:", reflect.Indirect(reflect.ValueOf(v)).Kind()) // prints interface

        // expect: struct
        fmt.Println("Indirect value type is:", reflect.Indirect(reflect.ValueOf(v)).Kind()) // prints interface
    }

    fmt.Println("")
}
2

2 Answers

19
votes

To get the struct value, you need to get the interface value's element:

fmt.Println("Indirect type is:", reflect.Indirect(reflect.ValueOf(v)).Elem().Type()) // prints main.CustomStruct

fmt.Println("Indirect value type is:", reflect.Indirect(reflect.ValueOf(v)).Elem().Kind()) // prints struct

playground example

This code is helpful for understanding the types in the example:

rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
    fmt.Println(rv.Kind(), rv.Type(), rv)
    rv = rv.Elem()
}
if rv.IsValid() {
    fmt.Println(rv.Kind(), rv.Type(), rv)
}

The output for &s is:

ptr *interface {} 0xc000010200
interface interface {} {}
struct main.CustomStruct {}

playground example

0
votes

use reflect.Indirect

package main

import (
    "fmt"
    "reflect"
)

func testFunc(value interface{}) {
    fmt.Println("---------------------")
    fmt.Println("type = " + reflect.ValueOf(value).Type().String())
    fmt.Println("kind = " + reflect.ValueOf(value).Kind().String())
    if reflect.ValueOf(value).Kind() == reflect.Ptr {
        fmt.Println("--> pointer ")
        pointsToValue := reflect.Indirect(reflect.ValueOf(value))
        fmt.Println("-->", pointsToValue.Kind(), " - ", pointsToValue.Type(), " - ", pointsToValue)
        if pointsToValue.Kind() == reflect.Slice {
            fmt.Println("--> slice !! ")
        }
    }
}

func main() {
    var testVar1 string
    var testVar2 []string
    var testVar3 []*string
    testVar2 = append(testVar2, "A")
    testVar2 = append(testVar2, "B")
    testFunc(testVar1)
    testFunc(testVar2)
    testFunc(testVar3)
    testFunc(testVar2)
    testFunc(&testVar2)
}
/*
---------------------
type = string
kind = string
---------------------
type = []string
kind = slice
---------------------
type = []*string
kind = slice
---------------------
type = []string
kind = slice
---------------------
type = *[]string
kind = ptr
--> pointer 
--> slice  -  []string  -  [A B]
--> slice !!
*/

https://play.golang.org/p/ysqIWQYyzn3