go reflectとslice
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)
type slice struct {
array unsafe.Pointer
len int
cap int
}
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]
上記のセクションによれば、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)
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)