为什么我不能用反射来获取切片的地址?

时间:2014-11-05 18:56:49

标签: reflection go slice

为什么会这样:

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

这也是:

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

但这并不是:

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

恐慌:reflect.Value.Addr of unaddressable value


编辑:总的来说,我尝试做的是采用一个未知类型的结构,制作一个这种类型的结构并返回一个指针(我使用github.com) / jmoiron / modl,它需要一个指向切片的指针来填充SQL查询的结果。)

1 个答案:

答案 0 :(得分:5)

reflect.Value需要interface{},并且interface{}的值不能用于更改原始值。否则,当您甚至打算将指针传递给它时,最终可能会在struct中更改代码更改数据。 (或者,在这种情况下,更改按值传递的切片的长度。)因此,如果您使用地址,则必须在ValueOf之前执行此操作。

要制作指向切片的指针,您可以将其传递给append到它的包(例如modl或Google App Engine GetMulti),您就可以了使用类似http://play.golang.org/p/1ZXsqjrqa3的内容,复制到这里:

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

reflect.Value中附加到{x}}的切片需要另外几行reflect,但听起来您正在使用的包会为您处理该部分。有关一般信息,执行追加的代码位于http://play.golang.org/p/m3-xFYc6ON及以下位置:

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