Почему golang отражает .MakeSlice возвращает не адресуемое значение

проверьте снимок ниже:

http://play.golang.org/p/xusdITxgT-

Почему это происходит? Поскольку один из моих аргументов должен быть адресом среза.

Возможно, я не дал понять всем.

collection.Find(bson.M{}).All(&result)

Вышеприведенный код - это то, почему мне нужен адрес среза.

переменная результата здесь - то, что мне нужно. Теперь я обычно могу это сделать

result := make([]SomeStruct, 10, 10)

Но теперь SomeStruct является динамическим, и мне нужно создать срез с помощью reflection.MakeSlice, So

result := reflect.MakeSlice(reflect.SliceOf(SomeType))

И это ошибки: результат должен быть адресом среза.

Ответы

Ответ 1

Как получить указатель на срез с использованием отражения

Простейшим решением, вероятно, является использование reflect.New() для создания указателя (полный пример игры):

my := &My{}

// Create a slice to begin with
myType := reflect.TypeOf(my)
slice := reflect.MakeSlice(reflect.SliceOf(myType), 10, 10)

// Create a pointer to a slice value and set it to the slice
x := reflect.New(slice.Type())
x.Elem().Set(slice)

collection.Find(bson.M{}).All(x.Interface())

Обратите внимание на x.Interface(), на который были указаны другие ответы. Это предотвращает, что вместо reflect.Value фактическое значение x передается на All().

Почему отражает .MakeSlice возвращает не адресуемое значение?

Свободное определение addressability в Go заключается в том, что вы можете взять адрес чего-то и гарантировать, что этот адрес указывает на то, что имеет смысл. Если вы выделяете что-то в стеке в теле функции, адрес выделенного значения в какой-то момент времени больше не будет доступен. Следовательно, это значение не адресуется. В большинстве случаев Go перемещает локальные переменные стека в кучу, если они возвращаются или иным образом продвигаются наружу, но во время выполнения это не выполняется. Поэтому CanAddr() возвращает только true, когда:

Значение адресуемое, если оно является элементом среза, элементом адресуемого массива, поле адресной структуры или результатом разыменования указателя.

У заявленных типов есть одна общая черта: они гарантируют, что то, что они держат, будет доступно извне и укажет на значимое значение в памяти. У вас нет ни среза, ни указателя, ни каких-либо других упомянутых вещей, так как вы создали локальный срез с помощью reflect.MakeSlice. Элементы упомянутого фрагмента будут адресованы хотя (поскольку память среза находится в куче).

Почему указатель на срез?

Главный вопрос для меня в этом случае заключался в том, почему API mgo требует указателя на фрагмент для iter.All? В конце концов, срезы являются ссылочными типами и для изменений в предоставленном наборе данных, никакой указатель не требуется. Но потом мне пришло в голову, что большую часть времени функция добавляет к фрагменту. Добавление приводит к распределению памяти, выделение памяти приводит к копированию старых данных в новую память, новая память означает новый адрес, который необходимо передать вызывающему.

Это поведение показано в этом примере в игре. По существу:

// Works. Uses available storage of the slice.
    resultv.Index(1).Set(a)

// Executes but changes are lost:   
//  reflect.Append(resultv, a)

// Does not work: reflect.Value.Set using unaddressable value
//  resultv.Set(reflect.Append(resultv, a))

Ответ 2

Я думаю, что вы после interface() Метод здесь, но я не уверен, почему вам нужно создать срез обратно типа через reflect.

package main

import (
    "fmt"
    "reflect"
)

type My struct {
    Name string
    Id   int
}

func main() {
    my := &My{}
    myType := reflect.TypeOf(my)
    slice := reflect.MakeSlice(reflect.SliceOf(myType), 10, 10).Interface()
    p := slice.([]*My)

    fmt.Printf("%T %d %d\n", p, len(p), cap(p))
}

Выдает:

[]*main.My 10 10

Игровая площадка