Изменить срез Голанга в другой функции - PullRequest
0 голосов
/ 23 октября 2019

У меня есть срез, если я удалю один элемент из него непосредственно в основной функции, длина среза будет сокращена на единицу. Но сделайте удаление в другой функции и вызвали ее в main, длина фрагмента все еще остается исходной. Кто может объяснить это для меня? Спасибо!

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    //copy(a[i:], a[i+1:])
    //a[len(a)-1] = 0
    //a = a[:len(a)-1]
    //fmt.Println(a)    //outputs: [2 3 4], this is correct

    f(a, i)
    fmt.Println(a) //outputs: [2 3 4 0], this is wrong!
}

func f(a []int, i int) {
    copy(a[i:], a[i+1:])
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a) //outputs: [2 3 4], here still correct
}

Go Playground Link

Ответы [ 2 ]

2 голосов
/ 23 октября 2019

Срез передается по значению, поэтому изменение его в вашей функции f не изменит его в функции main. Вы можете пройти по указателю, например так:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    f(&a, i)
    fmt.Println(a)    //outputs: [2 3 4], correct
}

func f(a *[]int, i int) {
    b := *a
    copy(b[i:], b[i+1:])
    // The following line seems pointless, but ok...
    b[len(b)-1] = 0
    b = b[:len(b)-1]
    fmt.Println(b)    //outputs: [2 3 4], here still correct
    *a = b
}

Go Playground

Как подсказывает @zerkms в комментариях, вы также можете вернуть новый фрагмент, избегаяиспользование указателей:

package main

import "fmt"

func main() {
    a := []int{1, 2, 3, 4}
    i := 0

    a = f(a, i)
    fmt.Println(a)
}

func f(a []int, i int) []int {
    copy(a[i:], a[i+1:])
    // The following line seems pointless, but ok...
    a[len(a)-1] = 0
    a = a[:len(a)-1]
    fmt.Println(a)     //outputs: [2 3 4], here still correct
    return a
}
0 голосов
/ 23 октября 2019

Не предлагая нового решения, просто пытаюсь объяснить, почему ваша программа ведет себя так, как вы просили:

Давайте сначала попытаемся понять, как работает встроенная функция 'copy'. Ссылка: [https://golang.org/pkg/builtin/#copy]

func copy(dst, src []Type) int

Встроенная функция копирования копирует элементы из исходного слайса в целевой слайс. (В особом случае он также будет копировать байты из строки в секцию байтов.) Источник и назначение могут перекрываться. Copy возвращает количество скопированных элементов, которое будет минимумом len (src) и len (dst).

Две вещи: 1. Сначала закомментируйте строку: // a [len (a) -1] = 0

Второе: поскольку вы используете один и тот же массив, то есть как источник и место назначения, вы получаете [2,3,4,4] в качестве вывода, поскольку массив назначения равен {1,2,3,4}, который был перезаписан на {2,3,4,4 (который уже есть)} вы можете попробовать использовать разные массивы, чтобы сделать его более понятным
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...