Как получить базовый массив среза в Go?

Допустим, у меня есть следующий массив целых 9X_go чисел длины 3:

nums := [3]int{1,2,3}

Затем я беру только первые 9X_string-slice два элемента

numSlice := nums[:2]

Вызов cap для numSlice и nums дает 9X_slice 3 в обоих случаях, а len возвращает 2 и 3 соответственно.

Если 9X_golang я затем добавлю к этому фрагменту (numSlice = append(numSlice, 10)), базовый 9X_string-slice массив (nums) станет [1 2 10]. cap остается равным 3 для 9X_jsonarray обоих, так как базовый массив среза тот 9X_slicing же, а длина среза теперь равна 3.

Однако, если 9X_slices я снова добавлю к этому фрагменту (numSlice = append(numSlice, 20)), базовый 9X_array массив фрагмента должен измениться - мы 9X_go-language видим, что это тот случай, когда cap теперь 9X_go удвоился для numSlice, а len теперь равно 9X_slicing 4.

Извините за переутомленное объяснение, я 9X_bytearray просто прогуливаюсь через него, но может 9X_bytearray ли кто-нибудь объяснить мне, что происходит 9X_jsonarray под капотом с базовым массивом и как получить 9X_golang ссылку на новый массив?

22
0
2
Общее количество ответов: 2

Ответ #1

Ответ на вопрос: Как получить базовый массив среза в Go?

Во-первых, если вы еще этого не сделали, вам 9X_string-slice следует прочитать this official blog post about slice internals. Это должно прояснить 9X_array-slice все.

Теперь для доступа к базовому массиву 9X_array вы можете использовать комбинацию reflect и unsafe. В 9X_go частности, reflect.SliceHeader содержит поле Data, которое содержит 9X_slice указатель на базовый массив фрагмента.

Пример 9X_slicing адаптирован из документации пакета unsafe:

s := []int{1, 2, 3, 4} hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s)) data := *(*[4]int)(unsafe.Pointer(hdr.Data)) 

27
2

  • Стоит отметить, что `Data` может указывать не на начало массива поддержки: только на 0-й элемент среза. Итак, в случае `numSlice: = nums ...

Ответ #2

Ответ на вопрос: Как получить базовый массив среза в Go?

В качестве предупреждения отвечу на ваш 9X_character-arrays второй вопрос. Начиная с Go 1.17, вы можете сделать 9X_go-language это так

(*[2]int)(numSlice) 

Playground

package main import ( "fmt" ) func main() { nums := [3]int{1, 2, 3} numSlice := nums[:2] underArr1 := (*[2]int)(numSlice) fmt.Println(&underArr1[0]) //0xc000016018 numSlice = append(numSlice, 10) underArr2 := (*[3]int)(numSlice) fmt.Println(&underArr2[0]) //0xc000016018 - same fmt.Println(nums) // [1 2 10] numSlice = append(numSlice, 20) underArr3 := (*[3]int)(numSlice) fmt.Println(&underArr3[0]) //0xc000078030 - different fmt.Println(cap(numSlice)) // 6 } 

Если честно, вам не нужно преобразовывать 9X_slices в указатель на массив, чтобы увидеть адреса, я 9X_arrays просто отвечу на ваш второй вопрос.

Поведение 9X_jsonarray действительно такое, как вы его описали. Когда 9X_string-slice вы добавляете 10, у вас все еще остается одно 9X_slicing поле в вашем базовом массиве (потому что 9X_slicing его длина равна 3, а ваш numSlice равен 9X_array-slice 2), и даже если он в настоящее время занят 9X_slicing 3, его можно использовать, и 3 перезаписывается 9X_slicing 10.

Когда вы добавляете 20, не остается полей, поэтому 9X_go он создает новый базовый массив (скорее 9X_character-arrays всего, 6 полей длиной, вдвое больше), копирует 9X_string-array туда все данные из исходного массива и перемещает 9X_golang указатель на этот массив.

2
0