反思思考结构价值也是一个ptr?

时间:2014-02-28 03:15:19

标签: reflection go

我有一个类似这个演示的数据结构。如您所见,foo有一个指向bar的嵌入式指针:

type foo struct {
    *bar
}

type bar struct {
    S []byte
}

我正在使用reflect这样的包:

func test(x interface{}) {

    var v = reflect.ValueOf(x)

    if v.Kind() == reflect.Struct {
        fmt.Println("was a struct")

    // panic: reflect: call of reflect.Value.Elem on struct Value
    //  v = v.Elem()

    // panic: reflect: call of reflect.Value.Field on ptr Value
        v = v.FieldByName("S")
    }
}

func main() {
    var f foo
    test(f)
    fmt.Println(string(f.S))
}

因此v.Kind()被识别为reflect.Struct,但如果我尝试使用.FieldByName("S")将其视为结构,则会发生恐慌,因为它认为v是{ {1}}。

那么,如果我尝试通过调用ptr将其视为ptr,那就会发生恐慌,因为它认为.Elem()v

我已尝试struct以及其他一些事情,但我无法弄清楚如何获取嵌入式指针的字段。

有没有办法从嵌入式指针获取reflect.Indirect()表示形式?

演示: http://play.golang.org/p/n0eea6XW3I


编辑 还尝试了reflect.Value,但得到了:

  

v = v.FieldByName("bar")

2 个答案:

答案 0 :(得分:7)

我们需要意识到的第一件事是var f foo行等同于f := foo{}。这会将内部字段bar(类型为* bar)初始化为零值... nil。嵌入类型和反射的行为似乎是它将嵌入类型的字段视为类型本身的字段。所以当你请求v.FieldByName("S")时,它试图在f的成员中找到该字段,bar,这是零。

您正在尝试执行此操作(*f.bar).S。 (在Go中,不需要显式指针解除引用,但它确实如此)。现在的问题是:如果你改为v.FieldByName("bar"),为什么会出错呢?同样的原因。

仔细查看堆栈跟踪,FieldByName行不再崩溃,崩溃的行是fmt.Println(string(f.S))。再一次,在语义上你正在做(*f.bar).S。但是成员“bar”是零,所以你实际上是在做一个nil指针取消引用。

您可以通过将var f foo更改为f := foo{&bar{}}来解决这两个错误。

答案 1 :(得分:0)

我收到了这个错误"恐慌:反映:关于结构价值的反思.Value.Elem"这行的bcz" reflect.ValueOf(parameterName).Elem()"

1.当我在反射中使用Elem()时,它意味着valueOf()中的parameterName应该是指向结构的指针

func Search(flight interface{}, key string) string {

  val := reflect.ValueOf(flight).Elem()

  for i := 0; i < val.NumField(); i++ {
    valueField := val.Field(i)
    typeField := val.Type().Field(i)
    if key == strings.ToLower(typeField.Name) {
      return valueField.Interface().(string)
    }
  }
  return ""
}

现在在调用搜索功能时,我的呼叫应该是这样的! 结果:=搜索(&amp; flight,key)