2014-10-09 31 views
2

我想傳遞給第三方包的結構中的字段指針的可變參數列表。該軟件包接受一個variadic interface{}列表(func Persist(...interface) error),其中每個接口值都是一個指向變量的指針。我創建了一個函數來模擬第三方庫如何打印Type和Kind指針(下面稱爲mockFunction)。獲取reflect.Ptr類型到字段在一個結構

當我以非可變的方式將結構變量的地址傳遞給它時,它們在使用反射調用的模擬函數內具有它們的基本類型和值。但是,當我使用擴展以可變方式傳遞它們時,它們具有Type: Type: reflect.ValueKind: struct。第三方軟件包不知道如何以這種形式處理它們。

我想找出一種方法來調用第三方封裝接口{}(如inv := make([]interface{}, 3)的切片和在電話會議上Persist(inv...)如果在所有可能使用可變參數的擴展。

下面是代碼一個鏈接到下面去遊樂場:

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 

有任何方式來構造切片定義和對放入切片的內容的調用,以便它可以進行可變擴展,並且看起來像是以無變化的方式將指針傳遞給結構字段?

回答

3

Addr()返回字段指針的反映Value。在值上調用Ptr()以將實際指針作爲接口{}。

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

playground

0

我想,也許去的處理這種情況已經從2014年開始改變 - 當然,上面的代碼,不再對我的作品與圍棋1.10 ...

但是以下代碼適用於我創建一個適當的[]interface{}使用描述的方式...

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()