Как создать массив с динамической длиной, а не срез в Голанге? - PullRequest
0 голосов
/ 27 июня 2018

Например: я хочу использовать отражение, чтобы получить данные среза в виде массива для его манипулирования.

func inject(data []int) {
    sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
    dh := (*[len(data)]int)(unsafe.Pointer(sh.Data))
    printf("%v\n", dh)
}

Эта функция выдаст ошибку компиляции, поскольку len(data) не является константой. Как мне это исправить?

1 Ответ

0 голосов
/ 27 июня 2018

Чтобы добавить к комментарию @ icza , вы можете легко извлечь базовый массив, используя &data[0] - предполагая, data - инициализированный фрагмент. Здесь нет необходимости перепрыгивать через обручи: адрес элемента первого среза фактически является адресом первого слота в базовом массиве среза - здесь нет никакой магии.

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

Единственное, что вы не можете сделать с указатель проходит вокруг результата разыменования. Это просто потому, что массивы в Go имеют свою длину, закодированную в их тип, поэтому вы не сможете создать функцию для принятия такой массив - потому что вы заранее не знаете длину массива.

Теперь, пожалуйста, остановитесь и подумайте.

После извлечения резервного массива из среза у вас есть указатель на память массива. Чтобы разумно носить его, вам также нужно носить с собой длина массива ... но это именно то, что делают срезы: они упаковывают адрес резервного массива с длиной данные в нем (а также емкость).

Следовательно, на самом деле я думаю, что вы должны пересмотреть свою проблему с того места, где я стою, я склонен думать, что это не проблема для начала.

Есть случаи , в которых используются указатели на массивы поддержки. извлеченные из кусочков могут помочь: например, при «объединении» такие массивы (скажем, через sync.Pool), чтобы уменьшить отток памяти в определенных ситуациях, но это конкретные проблемы. Если у вас есть конкретная проблема, пожалуйста, объясните , не твоя попытка решить эту проблему - что сказал @Flimzy.


Обновление Я думаю, что я должен быть лучше объяснить

вы не можете сделать с указатель проходит вокруг результата разыменования.

немного.

Критический момент о массивах в Go (в отличие от срезов) что массивы - как и все в Go - передаются по значению и для массивов, что означает, что их данные копируются.

То есть, если у вас есть

var a, b [8 * 1024 * 1024]byte
...
b = a

утверждение b = a действительно скопирует 8 МБ данных. То же самое относится и к аргументам функций.

Ломтики обходят эту проблему, удерживая указатель в базовый (резервный) массив. Так что значение среза это маленький struct тип, содержащий указатель и два целых числа. Следовательно копирование это действительно дешево, но "взамен" это имеет ссылочную семантику: исходное значение и его точка копирования в том же массиве поддержки, то есть ссылаться на те же данные.

Я действительно советую вам прочитать эти две части, в указанном порядке:

  1. https://blog.golang.org/go-slices-usage-and-internals
  2. https://blog.golang.org/slices
...