为什么我不能使用反射来获取切片的地址? [英] why can't I use reflection to take the address of a slice?

查看:544
本文介绍了为什么我不能使用反射来获取切片的地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



  slice:= make([] string,0,10)
sliceptr :=& slice



  sliceptr:=& [] string {foo,bar,baz} 

但这不是:

  sliceaddrval:= reflect.ValueOf([]字符串{foo,bar,baz})。Addr()

与: reflect.Value.Addr of unaddressable value






编辑:总的来说,我试图做的是采取一个未知类型的结构,做一个该类型的结构片,并返回一个指针(我使用github.com/jmoiron/modl需要一个指针以分片填充来自SQL查询的结果)。

解决方案

reflect.Value 将一个界面{} 和一个界面{} 设置为一个值,不能用于更改原本的。否则,如果您甚至不打算将指针传递给 struct ,那么您最终可能会更改代码。 (或者,在这种情况下,改变按值传递的片段的长度。)因此,如果您输入地址,您必须在 ValueOf 之前执行此操作。

制作一个指向切片的指针,您可以将它传递给一个包含的附加的包(比如 modl 或Google App Engine GetMulti ),您可以使用类似 http://play.golang.org/p/1ZXsqjrqa3 ,复制于此:

 










$ b $ row struct {i,j int}

func main(){
Row:= row {}
$ b valueType:= reflect.ValueOf(aRow).Type ()
slicePtrVal:= reflect.New(reflect.SliceOf(valueType))
slicePtrIface:= slicePtrVal.Interface()

getQueryResults(slicePtrIface)
fmt。 println(slicePtrIface)
}

//代表`modl`或其他填充切片
func getQueryResults(slicePtr interface {}){
sPtr:= (* [] row)
(* sPtr)= append((* sPtr),row {1,3})
}
pre>

添加到 reflect.Value 中的切片时,您自己需要再加几行反映,但听起来你正在使用的软件包会为你处理该部分。对于一般信息,执行附加操作的代码位于 http://play.golang.org/p/ m3-xFYc6ON 和以下:

  package main 

import(
fmt
反映


行结构{i,j int}

func main(){
aRow := row {}

//创建一个指向空片的指针
rowType:= reflect.ValueOf(aRow).Type()
slicePtrVal:= reflect.New reflect.SliceOf(rowType))
slicePtrIface:= slicePtrVal.Interface()

//追加零行
rowVal:= reflect.Zero(rowType)
sliceVal:= reflect.Indirect(slicePtrVal)
sliceVal.Set(reflect.Append(sliceVal,rowVal))

fmt.Println(slicePtrIface)
}


How come this works:

slice := make([]string, 0, 10)
sliceptr := &slice

this too:

sliceptr := &[]string{"foo","bar","baz"}

But this doesn't:

sliceaddrval := reflect.ValueOf([]string{"foo","bar","baz"}).Addr()

It panics with: reflect.Value.Addr of unaddressable value


EDIT: Overall what I'm trying to do is take a struct that is of an unknown type, make a slice of structs of that type and return a pointer to it (I'm using github.com/jmoiron/modl which requires a pointer to slice to populate with results from a SQL query).

解决方案

reflect.Value takes an interface{}, and an interface{} to a value can't be used to change the original. Otherwise, you could end up with code changing data in your struct when you didn't even intend to pass it a pointer. (Or, in this case, changing the length of a slice that was passed by value.) So if you take the address you'd have to do it before the ValueOf.

To make a pointer to a slice that you can to pass to a package that will append to it (like modl or Google App Engine GetMulti), you'd use something like http://play.golang.org/p/1ZXsqjrqa3, copied here:

package main

import (
    "fmt"
    "reflect"
)

type row struct { i, j int }

func main() {
    aRow := row{}

    valueType := reflect.ValueOf(aRow).Type()
    slicePtrVal := reflect.New(reflect.SliceOf(valueType))
    slicePtrIface := slicePtrVal.Interface()

    getQueryResults(slicePtrIface)
    fmt.Println(slicePtrIface)
}

// standing in for `modl` or whatever populates the slice
func getQueryResults(slicePtr interface{}) {
    sPtr := slicePtr.(*[]row)
    (*sPtr) = append((*sPtr), row{1,3}) 
}

Appending to a slice in a reflect.Value yourself takes another few lines of reflect, but it sounds like the package you're working with takes care of that part for you. For general info, code to do the append is at http://play.golang.org/p/m3-xFYc6ON and below:

package main

import (
    "fmt"
    "reflect"
)

type row struct { i, j int }

func main() {
    aRow := row{}

    // make a pointer to an empty slice
    rowType := reflect.ValueOf(aRow).Type()
    slicePtrVal := reflect.New(reflect.SliceOf(rowType))
    slicePtrIface := slicePtrVal.Interface()

    // append a zero row to it
    rowVal := reflect.Zero(rowType)
    sliceVal := reflect.Indirect(slicePtrVal)
    sliceVal.Set(reflect.Append(sliceVal, rowVal))

    fmt.Println(slicePtrIface)
}

这篇关于为什么我不能使用反射来获取切片的地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆