2017-12-17 7 views
0

指定された構造体の各属性にポインタのスライスを取得する方法が見つかりません。あなたが見ることができるように私は私のポインタを取得するためにリフレクションを使用しています(https://stackoverflow.com/a/24348352/6093604のおかげで)uintptrをリフレクションからポインタ(*)に変換する

if valueField.CanAddr() { 
    address = fmt.Sprintf("0x%X", valueField.Addr().Pointer()) 
} 

は、valueField.Addr()。ポインタは、()のポインタaddrの値が、しかし、リフレクションを使用して、私が取得したいと思い返しますsql.Rows.Scan()

のために使用可能なポインタは、それでは私がやったことです:

func StructAttributesToPointersSlice(object interface{}) []interface{} { 

    val := reflect.ValueOf(object) 

    if val.Kind() == reflect.Interface && !val.IsNil() { 
     elm := val.Elem() 
     if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr { 
      val = elm 
     } 
    } 
    if val.Kind() == reflect.Ptr { 
     val = val.Elem() 
    } 

    var ptrs []interface{} 
    for i := 0; i < val.NumField(); i++ { 
     valueField := val.Field(i) 

     if valueField.Kind() == reflect.Ptr { 
      valueField = valueField.Elem() 

     } 
     if valueField.CanAddr() { 
      ptrs = append(ptrs, valueField.Addr().Pointer()) 
     } 
    } 

    return ptrs 
} 

しかし、私はScan() SQL関数のためにそれを使用しよう:

var values []interface{} 

// Iterate over each rows got from the query 
for rows.Next() { 

    ptrs := utils.StructAttributesToPointersSlice(&newObject) 

    for _, item := range ptrs { 
     fmt.Println(reflect.TypeOf(item)) 
    } 

    err = rows.Scan(ptrs...) 
    if err != nil { 
     return nil, model.Status{Code: http.StatusInternalServerError, Error: err.Error()} 
    } else { 
     values = append(values, newObject) 
    } 
} 

私はこのエラーを取得しています:

sql: Scan error on column index 0: destination not a pointer

私はそれが使用可能なポインタにそれを変換する方法、それはuintptrだからいいタイプではないですが、からだと知っていますか?

おかげ

+0

ADDR()既にポインタ値を返します。ポインタを呼び出すことは間違っています。おそらくPointer()の代わりにInterface()を介して実際のポインタを抽出する必要があります。 – Volker

答えて

0

いくつかのタイプのポインタにuintptrを変換するために使用unsafe.Pointer。一例として、以下の式はTポインタにu uintptr変換:

(*T)(unsafe.Pointer(u)) 

構造体のフィールドは、任意のタイプのものとすることができるので、この変換はStructAttributesToPointersSliceに役立ちません。また、uintptrからの変換は不要で安全ではありません。

valueField.Addr()は、フィールドへのポインタのreflect.Valueです。実際のポインタを取得するにはInterface()に電話してください。

func StructAttributesToPointersSlice(object interface{}) []interface{} { 
    v := reflect.ValueOf(object) 
    if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { 
     panic("argument must be a pointer to struct") 
    } 

    v = v.Elem() 
    var result []interface{} 
    for i := 0; i < v.NumField(); i++ { 
     f := v.Field(i) 
     if !f.CanSet() { 
      continue 
     } 
     result = append(result, f.Addr().Interface()) 

    } 
    return result 
} 

このコードに関するいくつかの注意事項:

  • 引数、プログラムを修正

    ptrs = append(ptrs, valueField.Addr().Interface()) 
    

    ptrs = append(ptrs, valueField.Addr().Pointer()) 
    

    を変更するには、ここでは機能の簡易版です構造体へのポインタでなければなりません。

  • フィールドでCanAddrを呼び出す必要はありません。構造体へのポインタのチェックはこれをカバーします。
  • CanSet()は、非公開のフィールドをスキップします。あなたは代わりにそれをパニックにしたいかもしれません。
  • 呼び出し元のエラーのために関数がパニックします。代わりにエラーを返すことを検討してください。

playground example

関連する問題