func main() {
a := []string{"Hello1", "Hello2", "Hello3"}
fmt.Println(a)
// [Hello1 Hello2 Hello3]
a = append(a[:0], a[1:]...)
fmt.Println(a)
// [Hello2 Hello3]
}
Как работает этот трюк с удалением с функцией добавления?
Казалось бы, он захватывает все до первого элемента (пустой массив)
Затем добавляем все после первого элемента (нулевая позиция)
Что делает ... (точка, точка)?
...
там подробно объясняется?Ответы:
Где
a
находится срез, аi
это индекс элемента, который вы хотите удалить:a = append(a[:i], a[i+1:]...)
...
- синтаксис для вариативных аргументов в Go.По сути, при определении функции она помещает все аргументы, которые вы передаете, в один фрагмент этого типа. Поступая так, вы можете передавать столько аргументов, сколько хотите (например,
fmt.Println
можете принимать столько аргументов, сколько хотите).Теперь при вызове функции
...
происходит обратное: он распаковывает срез и передает их как отдельные аргументы в вариационную функцию.Итак, что делает эта строка:
a = append(a[:0], a[1:]...)
по сути:
a = append(a[:0], a[1], a[2])
Теперь вам может быть интересно, почему бы просто не сделать
a = append(a[1:]...)
Ну, функция определения
append
являетсяfunc append(slice []Type, elems ...Type) []Type
Таким образом, первый аргумент должен быть срезом правильного типа, второй аргумент - вариативным, поэтому мы передаем пустой срез, а затем распаковываем остальную часть среза, чтобы заполнить аргументы.
источник
a = append(a[:i], a[i+1:]...)
Есть два варианта:
A: Вы заботитесь о сохранении порядка в массиве:
a = append(a[:i], a[i+1:]...) // or a = a[:i+copy(a[i:], a[i+1:])]
B: Вы не заботитесь о сохранении порядка (это, вероятно, быстрее):
a[i] = a[len(a)-1] // Replace it with the last one. CAREFUL only works if you have enough elements. a = a[:len(a)-1] // Chop off the last one.
См. Ссылку, чтобы увидеть последствия утечки памяти, если ваш массив состоит из указателей.
https://github.com/golang/go/wiki/SliceTricks
источник
Вместо того, чтобы рассматривать индексы в
[a:]
-,[:b]
- и[a:b]
-notations как индексы элементов, думайте о них как о индексах промежутков вокруг и между элементами, начиная с промежутка, индексированного0
перед элементом, индексированным как0
.Глядя только на синие числа, гораздо легче понять, что происходит:
[0:3]
все окружает,[3:3]
пусто и[1:2]
уступит{"B"}
. Тогда[a:]
это всего лишь короткая версия[a:len(arrayOrSlice)]
,[:b]
короткая версия[0:b]
и[:]
короткая версия[0:len(arrayOrSlice)]
. Последний обычно используется для превращения массива в срез, когда это необходимо.источник
... это синтаксис для вариативных аргументов.
Я думаю, что это реализовано компилятором с помощью slice (
[]Type)
, как и функция append:func append(slice []Type, elems ...Type) []Type
когда вы используете "elems" в "append", на самом деле это срез (тип []). Итак, "
a = append(a[:0], a[1:]...)
" означает "a = append(a[0:0], a[1:])
"a[0:0]
это кусок, в котором ничего нетa[1:]
это "Hello2 Hello3"Вот как это работает
источник
a[0:0]
это неnil
кусок с нулевой длиной.a[0:0]
будет только быть ,nil
еслиa
естьnil
.Я получаю сообщение об ошибке индекса вне допустимого диапазона с принятым ответом. Причина: когда начинается диапазон, это не итерация значений по одному, а итерация по индексу. Если вы изменили срез, пока он находится в пределах досягаемости, это вызовет некоторые проблемы.
Старый ответ:
chars := []string{"a", "a", "b"} for i, v := range chars { fmt.Printf("%+v, %d, %s\n", chars, i, v) if v == "a" { chars = append(chars[:i], chars[i+1:]...) } } fmt.Printf("%+v", chars)
Ожидается:
[a a b], 0, a [a b], 0, a [b], 0, b Result: [b]
Актуально:
// Autual [a a b], 0, a [a b], 1, b [a b], 2, b Result: [a b]
Правильный способ (решение):
chars := []string{"a", "a", "b"} for i := 0; i < len(chars); i++ { if chars[i] == "a" { chars = append(chars[:i], chars[i+1:]...) i-- // form the remove item index to start iterate next item } } fmt.Printf("%+v", chars)
Источник: https://dinolai.com/notes/golang/golang-delete-slice-item-in-range-problem.html
источник
В вики golang показаны некоторые приемы для среза, включая удаление элемента из среза.
Ссылка: введите описание ссылки здесь
Например, a - это фрагмент, который вы хотите удалить элементом i.
a = append(a[:i], a[i+1:]...)
ИЛИ
a = a[:i+copy(a[i:], a[i+1:])]
источник