在Go结构中获取reflect.Ptr类型到字段

时间:2014-10-09 20:13:20

标签: reflection go

我正在尝试向第三方包传递一个指向结构中字段的可变参数列表。该包接受可变interface{}列表(func Persist(...interface) error),其中每个接口值都是指向变量的指针。我创建了一个函数来模拟第三方库并打印出指针的类型和种类(下面称为mockFunction)。

当我以非变量方式传递结构变量的地址时,它们使用反射调用在模拟函数中具有它们的原始类型和值。但是,当我使用扩展以可变方式传递它们时,它们具有Type: Type: reflect.ValueKind: struct。第三方软件包不知道如何以这种形式处理它们。

我想找出一种方法来使用一个接口{}来调用第三方包(例如inv := make([]interface{}, 3),并且如果可能的话,在调用Persist(inv...)上使用可变扩展。< / p>

以下是带有Go Playground链接的代码:

package main

import (
  "fmt"
  "reflect"
)

type Investment struct {
  Price  float64
  Symbol string
  Rating int64
}

func main() {
  inv := Investment{Price: 534.432, Symbol: "GBG", Rating: 4}
  s := reflect.ValueOf(&inv).Elem()
  variableParms := make([]interface{}, s.NumField())
  for i := 0; i < s.NumField(); i++ {
    variableParms[i] = s.Field(i).Addr()
  }

  // non-variadic call
  mockFunction(&inv.Price, &inv.Symbol, &inv.Rating)
  //variadic call
  mockFunction(variableParms...)
}

func mockFunction(values ...interface{}) {
  for i, value := range values {
    rv := reflect.ValueOf(value)
    fmt.Printf("value %d has Type: %s and Kind %s\n", i, rv.Type(), rv.Kind())
  }
}

Go Playground Link

当我使用非可变参数运行它时,对mockFunction的调用返回本机类型和种类,第三方包处理它们很好:

value 0 has Type: *float64 and Kind ptr
value 1 has Type: *string and Kind ptr
value 2 has Type: *int64 and Kind ptr

当我使用可变参数运行它时,值是不同的,第三方包不知道如何处理这些类型:

value 0 has Type: reflect.Value and Kind struct
value 1 has Type: reflect.Value and Kind struct
value 2 has Type: reflect.Value and Kind struct

是否有任何方法可以构造切片定义以及对切片中放置的内容进行调用,以便可以对其进行可变扩展,看起来像是以非变量方式将指针传递给struct字段?

2 个答案:

答案 0 :(得分:3)

Addr()返回字段指针的反射Value。在值上调用Ptr()以将实际指针作为接口{}。

variableParms[i] = s.Field(i).Addr().Ptr()

playground

答案 1 :(得分:1)

我认为,自2014年以来,Go对此案件的处理方式也发生了变化 - 当然,上面的代码对我来说不再适用于Go 1.10 ......

但是,以下代码可以帮我创建一个合适的func settableSliceFromStruct(inStruct interface{}) ([]interface{}, error) { t := reflect.TypeOf(inStruct) if t.Kind() != reflect.Ptr { return nil, errors.New("can only assign values with pointer to struct") } v := reflect.ValueOf(inStruct).Elem() t = t.Elem() dataColumns := make([]interface{}, 0, t.NumField()) for i := 0; i < t.NumField(); i++ { if weWantToIncludeThis(t.Field(i)) { dataColumns = append(dataColumns, v.Field(i).Addr().Interface()) } } return dataColumns, nil } 以便按照描述的方式使用...

variableParms[i] = s.Field(i).Addr().Interface()

这里的关键部分是您的代码:

{{1}}