Неявные ссылки (указатели) в Go
Решаю простые задачки на CodeWars. Возникла проблема со следующей частью кода:
func FindOutlier(integers []int) int {
coping := integers //делаем копию массива
var DosZeroCount int = 0
var DosZeroNotCount int = 0
for index, _ := range coping {
coping[index] = coping[index] % 2
if coping[index] == 1 {
DosZeroNotCount++
} else {
DosZeroCount++
}
}//обнуляется integers без одного элемента
Проблема заключается в том, что coping - получается неявной ссылкой исходного массива. Согласно описанию языка такое действие coping := integers должно полностью копировать массив, а не создавать ссылку на него. Каким образом можно скопировать массив полностью? Подозреваю, что дело в том, что integers - аргумент функции...
Ответы (1 шт):
работа с массивами и map-ами отличается и нужно знать несколько правил.
coping := integers работает внутри range, когда вы меняете состояние элемента, но не хотите, чтобы в map-е или в массиве оно менялось.
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k, v := range m {
copyOfValue := v
copyOfValue = 10
v = 11
fmt.Printf("copyOfValue: %s: %d\n", k, copyOfValue)
break
}
fmt.Printf("m: %v\n", m)
copyOfValue: c: 10
m: map[a:1 b:2 c:3]
for i := range a и for i, v := range &a никогда не создают копию a, но вот for i, v := range a создает копию)) просто нужно запомнить. Вот убедитесь сами
func IndexArray() {
a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
for i := range a {
a[3] = 100
if i == 3 {
fmt.Println("IndexArray", i, a[i])
}
}
}
func IndexValueArray() {
a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
for i, v := range a {
a[3] = 100
if i == 3 {
fmt.Println("IndexValueArray", i, v)
}
}
}
func IndexValueArrayPtr() {
a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
for i, v := range &a {
a[3] = 100
if i == 3 {
fmt.Println("IndexValueArrayPtr", i, v)
}
}
}
func main() {
IndexArray()
IndexValueArray()
IndexValueArrayPtr()
}
IndexArray 3 100
IndexValueArray 3 4
IndexValueArrayPtr 3 100
ссылка чтобы поиграться
поэтому, самый простой способ сделать копию массива - это
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
numberOfElementsCopied := copy(dst, src)
теперь поговорит про слайсы(slice)
В Golang есть понятия slice - это почти как массив, только ведет себя не как массив. Например, в следующем коде будет копия
arr1:=[...]int{1,2,3}
arr2:=arr1
arr1[1]=99
fmt.Println(arr1)
fmt.Println(arr2)
[1 99 3]
[1 2 3]
но если "копирвоание" изменить так, то изменится и исходный массив
arr1:=[...]int{1,2,3}
arr2:=arr1[:]
arr1[1]=99
fmt.Println(arr1)
fmt.Println(arr2)
[1 99 3]
[1 99 3]
А все потому, что слайс - это указатель на массив(точнее каждый элемент нового слайся ссылается на элемент исходного).
Slicing does not copy the slice's data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice
Вот источник
Итого, чтобы не запутались
array := [5]int{1, 2, 3, 4, 5} // это массив
slice := array[:] // это срез массива
slice := [...]int{1, 2, 3, 4, 5} // это срез массива
slice := int{1, 2, 3, 4, 5} // это срез массива