如何从接口获取chan值并在reflect中使用它。选择(...)

时间:2016-06-15 23:28:32

标签: go

我举了一个反映的例子。选自:  的 https://www.socketloop.com/references/golang-reflect-select-and-selectcase-function-example

它尽可能地发挥作用。但它是从一个简单的创建reflect.Value() " CHAN" := make(chan int)设置。

但我想使用来自作为接口{}传递的结构的通道。

所以我修改了程序来创建一个结构并将其传递给处理 接口参数。

运行时,我得到:恐慌:反映:关于struct的调用.Value.Elem。值得反映:对结构值调用reflect.Value.Elem

这很奇怪,因为我确切的代码是另一个有效的程序!!

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
}

可以吗? 身体告诉我在尝试使用接口代码时出错了 取代简单的变量版本。

该程序如下所示,注释显示更改:

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++
        }
    }
}

1 个答案:

答案 0 :(得分:1)

执行此操作的一种方法是不进行反射,而是键入断言。所以你可以说:

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

或者,如果您坚持使用reflect(这是一个较差的解决方案),您可以通过删除Elem()来获得所需内容。例如:

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

如果您不想使用该名称,甚至可以val.Field(0)。同样,类型断言方法比这更好。