如何从接口获取chan值并将其用于reflect.Select(…)

I took an example of reflect.Select from: https://www.socketloop.com/references/golang-reflect-select-and-selectcase-function-example

It works as far as it goes. But it was creating the reflect.Value() from a simple "chan" := make(chan int) setup.

But I wanted to use a channel from a structure passed as an interface{}.

So I modified the program to create a struct and pass it to the processing as an interface parameter.

When run I get: panic: reflect: call of reflect.Value.Elem on struct Valuepanic: reflect: call of reflect.Value.Elem on struct Value

This is strange because I the exact code another program that works!!

func inspect(f interface{}) map[string]string {

    m := make(map[string]string)
    val := reflect.ValueOf(f).Elem()

    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        typeField := val.Type().Field(i)
        f := valueField.Interface()

        val := reflect.ValueOf(f)
        m[typeField.Name] = val.String()
    }

    return m
}

Can any body tell me where I am going wrong trying to use the interface code in replace of the simple variable version.

The program is below with comments showing changes:

package main

// Original Example from:
// https://www.socketloop.com/references/golang-reflect-select-and-selectcase-function-example
//
import (
    "fmt"
    "reflect"
)

func main() {

    // following replaces  " var sendCh := make(chan int) "
    type Foo struct {
        Ch chan int
    }
    sendCh := Foo{make(chan int)}
    // End of replacement code

    var increaseInt = func(c chan int) {
        for i := 0; i < 8; i++ {
            c <- i
        }
        close(c)
    }

    go increaseInt(sendCh.Ch)

    // This routine call replaces the code incorporated in "runJob"
    // It was done so I could call through an empty interface{}
    runJob(sendCh)
    // End replaement code--
}

func runJob(f interface{}) {
    var selectCase = make([]reflect.SelectCase, 1)

    // This code replaces just using the orginal "sendCh" value
    // I am trying here to construct "sendCh" from the interface value
    val := reflect.ValueOf(f).Elem()
    valueField := val.Field(0)
    sendCh := valueField.Interface()
    // End of replacement code

    selectCase[0].Dir = reflect.SelectRecv
    selectCase[0].Chan = reflect.ValueOf(sendCh)

    counter := 0
    for counter < 1 {
        chosen, recv, recvOk := reflect.Select(selectCase) // <--- here
        if recvOk {
            fmt.Println(chosen, recv.Int(), recvOk)

        } else {
            fmt.Println("Exit Condition Detected:  ", chosen, recv.Int(), recvOk)
            counter++
        }
    }
}

One way to do this is to not do reflection but do type assertion instead. So you could say:

val, ok := f.(Foo)
if !ok {
    fmt.Printf("Not Foo? Try Bar.
")
}
sendCh := val.Ch

Alternatively, if you insist on using reflect (which is an inferior solution here) you could get what you want by dropping Elem(). For example:

val := reflect.ValueOf(f)
valueField := val.FieldByName("Ch")
sendCh := valueField.Interface()

Or even val.Field(0) if you don't want to use the name. Again, the type assertion method is better than this.