go reflectとslice

3010 ワード

1. slice


sliceの最下位ストレージの構造は、次のとおりです.
type slice struct {
        array unsafe.Pointer
        len   int
        cap   int
}

まず、sliceオブジェクトの理解を深める記事を提供します.
https://segmentfault.com/a/1190000017910165?utm_source=sf-related
 go1.13.8 linux/amd64, :
func testsliceInt(sliceInt []int) {
    fmt.Printf("testslice: &sliceInt addr:%p
", &sliceInt) fmt.Printf("testslice: sliceInt array addr:%p, val:%v
", sliceInt, sliceInt) sliceInt[0] = 11 fmt.Printf("testslice: sliceInt array addr:%p, val:%v
", sliceInt, sliceInt) sliceInt = append(sliceInt, 12) fmt.Printf("testslice: sliceInt array addr:%p, val:%v
", sliceInt, sliceInt) } func main(){ sliceInt := make([]int, 1, 2) sliceInt[0] = 10 fmt.Printf("&sliceInt addr:%p
", &sliceInt) length := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&sliceInt)) + uintptr(8))) cap := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&sliceInt)) + uintptr(16))) fmt.Printf("sliceInt.len val:%v
", length) fmt.Printf("sliceInt.cap val:%v
", cap) fmt.Printf("sliceInt array addr:%p, val:%v
", sliceInt, sliceInt) testsliceInt(sliceInt) fmt.Printf("sliceInt array addr:%p, val:%v
", sliceInt, sliceInt) } : &sliceInt addr:0xc00000c220 sliceInt.len val:1 sliceInt.cap val:2 sliceInt array addr:0xc000018090, val:[10] testslice: &sliceInt addr:0xc00000c280 testslice: sliceInt array addr:0xc000018090, val:[10] testslice: sliceInt array addr:0xc000018090, val:[11] testslice: sliceInt array addr:0xc000018090, val:[11 12] sliceInt array addr:0xc000018090, val:[11]

前述のドキュメント実験と一致するのは,go関数sliceの伝達は実際には値伝達であるため,下位配列のアドレスのみが伝達されるため,下位配列の内容の修正は伝達できる.しかし、異なる点は、appendの値が戻らない限り、まだ拡張されていないとしても.
しかし結論には影響せず,関数内でappendに関わる限りsliceのポインタで伝達しなければならない.

2.所定のタイプに応じて対応するタイプのsliceポインタを生成する


上記のセクションによれば、sliceオブジェクトで渡され、appendで渡される限り、sliceポインタを渡さなければなりません.実際のシーンの例を示します.
//golang mongo driver: 
collection.Find(bson.M{}).All(result) // result slice ,api interface{}

既存のTest構造体は以下の通りである.
type Test struct{
    Name string
}

通常、ユーザーはvar result*[]Testを直接呼び出すことができます.
ただし、ミドルウェアによって変換される場合、具体的な構造タイプは不明です.この場合、reflect関数を使用して生成できます.
 var value interface{} = Test{}
    sliceType := reflect.SliceOf(reflect.TypeOf(value))
    slice:= reflect.MakeSlice(sliceType, 0, 0)
    slicedata := reflect.New(slice.Type())
    slicedata.Elem().Set(slice)
    data :=slicedata.Interface()

このときdataはパラメータとして入力できます

3.シミュレーションmongo未知タイプのsliceポインタの処理

func dealsliceptr(value interface{}) {
    val := reflect.ValueOf(value)
    ind := reflect.Indirect(val)
    tmpslice := ind
    tmpslice = reflect.Append(tmpslice, reflect.ValueOf(Test{Name: "test"}))
    ind.Set(tmpslice)