2017-02-20 4 views
0

Возвращаемое значение slice2 этого кода [[1 1] [1 1]].
И это меня путало, потому что я ожидал [[0 0] [1 1]].
Я не могу понять, почему возвращается [[1 1] [1 1]], а не [[0 0] [1 1]].
Буду признателен, если кто-нибудь сможет это объяснить. Благодарю.Golang slice добавляет встроенную функцию, возвращающую значение

slice := []int{0, 0} 
slice2 := [][]int{} 

for i := range slice { 
    slice[0] = i 
    slice[1] = i 
    slice2 = append(slice2, slice) 
} 
fmt.Println(slice2) 

Вы можете проверить код в этой ссылке play.golang.org

ответ

1

A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).

В вашем случае Ваш, добавляя ломтик (указатель) не значения среза. Чтобы получить желаемый результат, вы должны объявить новый срез на каждой итерации и добавить новый срез на slice2.

func main() { 
    slice := []int{0, 0} 
    slice2 := [][]int{} 

    for i := range slice { 
     ns := []int{0, 0} 
     ns[0] = i 
     ns[1] = i 
     slice2 = append(slice2, ns) 
    } 
    fmt.Println(slice2) // Outputs: [[0 0] [1 1]] 
} 

Playground

1

Когда вы пробегаете срез, это не дает вам значение среза, это дает вам индексы. Этот цикл цикла эквивалентен for i:=0; i < len(slice); i++ {}. Таким образом, к тому времени, когда он проходит через итерацию, оба значения находятся в slice: 1, и вы добавили его к slice2 дважды.

Если вам нужны значения среза, вам нужно будет сделать for i, v := range slice {}, который даст вам как индексы, так и значения. Вы можете использовать _ вместо i, если вы не хотите индекса.

Также обратите внимание, что добавление slice в два раза аналогично этому добавляет один и тот же точный фрагмент, потому что срезы выделяются как указатели на кучу, и поэтому это указатель на срез. Таким образом, slice2[0] == slice2[1], потому что это тот же точный срез.

+1

В частности, 'slice' представляет собой структуру с 3 полями: указатель на базовый массив, мощностью и длиной. Поскольку вы обновляете элементы среза по индексу, вы изменяете базовый массив. Поскольку вы добавляете один и тот же срез дважды, оба относятся к одному и тому же базовому массиву, поэтому изменение значений во второй итерации цикла изменяет то, что имеет первый срез, и значения. – Kaedys

0

Проблема заключается в том, что вы добавите к slice2 является ссылка к slice, а не значения, содержащиеся в slice в момент вызова.

Это означает, что в конце slice2 содержит два указателя на один и тот же срез. Любые изменения в переменной slice будут отображены в slice2 и наоборот: они указывают на то же место в памяти.

В качестве доказательства, просто сделать:

slice2[0][1] = 2 
fmt.Println(slice2) 
fmt.Println(slice) 

Вы получите:

[[1 2] [1 2]] 
[1 2] 
+0

Спасибо за ваше объяснение. Теперь все имеет смысл. –

Смежные вопросы