Go 删除切片中的元素
这个带有append函数的删除技巧是如何工作的 它似乎在抓取第一个元素(空数组)之前的所有内容 然后在第一个元素之后追加所有内容(位置零)Go 删除切片中的元素,go,Go,这个带有append函数的删除技巧是如何工作的 它似乎在抓取第一个元素(空数组)之前的所有内容 然后在第一个元素之后追加所有内容(位置零) 什么是。。。(dot-dot)do?其中a是切片,i是要删除的元素的索引: func main() { a := []string{"Hello1", "Hello2", "Hello3"} fmt.Println(a) // [Hello1 Hello2 Hello3] a = append(a[:0], a[1:]...)
什么是。。。(dot-dot)do?其中
a
是切片,i
是要删除的元素的索引:
func main() {
a := []string{"Hello1", "Hello2", "Hello3"}
fmt.Println(a)
// [Hello1 Hello2 Hello3]
a = append(a[:0], a[1:]...)
fmt.Println(a)
// [Hello2 Hello3]
}
…
是Go中可变参数的语法
基本上,定义函数时,它会将传递的所有参数放入该类型的一个切片中。通过这样做,您可以传递任意数量的参数(例如,fmt.Println
可以接受任意数量的参数)
现在,当调用函数时,…
的作用正好相反:它解压一个切片,并将其作为单独的参数传递给变量函数
这条线的作用是:
a = append(a[:i], a[i+1:]...)
基本上是:
a = append(a[:0], a[1:]...)
现在,你可能会想,为什么不这样做呢
a = append(a[:0], a[1], a[2])
那么,append
的函数定义是
a = append(a[1:]...)
因此,第一个参数必须是正确类型的切片,第二个参数是变量,因此我们传入一个空切片,然后解压切片的其余部分以填充参数。。。。是可变参数的语法 我认为它是由编译器使用slice(
[]Type)
实现的,就像函数append:
func append(slice []Type, elems ...Type) []Type
当您在“append”中使用“elems”时,实际上它是一个切片([]类型)。
所以“a=append(a[:0],a[1:]…)
”意味着“a=append(a[0:0],a[1:])
”
a[0:0]
是一个什么都没有的片
a[1:][/code>是“Hello2 Hello3”
这就是它的工作原理有两种选择:
答:您关心的是保留数组顺序:
func append(slice []Type, elems ...Type) []Type
B:你不在乎保留订单(这可能更快):
如果数组是指针数组,请参阅链接以查看内存泄漏的影响
在golang的wiki中,它展示了slice的一些技巧,包括从slice中删除元素
链接:
例如,a是要删除数字i元素的切片
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.
或
不要将[a://code>-、[:b]
-和[a:b]
-符号中的索引视为元素索引,而应将它们视为元素周围和元素之间间隙的索引,从间隙索引0
开始,然后将元素索引为0
只看蓝色的数字,就更容易看到发生了什么:[0:3]
包含所有内容,[3:3]
为空,[1:2]
将产生{“B”}
。然后[a::
只是[a:len(arrayorsicle)]
的短版本,[:b]
是[0:b]
的短版本,[:]
是[0:len(arrayorsicle)]
的短版本。后者通常用于在需要时将数组转换为切片。我得到了一个索引超出范围的错误,并使用了可接受的答案解决方案。
原因:
当范围开始时,它不是逐个迭代值,而是按索引迭代。
如果在切片处于范围内时对其进行修改,则会导致一些问题
旧答案:
a = a[:i+copy(a[i:], a[i+1:])]
预期:
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]
正确的方法(解决方案):
chars:=[]字符串{“a”、“a”、“b”}
对于i:=0;i/形成删除项索引以开始迭代下一项
}
}
格式打印F(“%+v”,字符)
来源:检查一下为什么不看看语言规范..
在这里有详细的解释吗?一方面,绝对正确(,每个人);另一方面,对于这些习语,对于移植蟒蛇等习语有很多不熟悉的地方,我不介意有一个解释让其他人去发现。参见a[0:0]
不是nil
,而是一个长度为0的片段<如果a
是nil
,则code>a[0:0]
将仅为nil
。如果i是slice中的最后一个元素,您不会得到超出范围的异常吗a=append(a[:i],a[i+1:]…)
@DaveC在我的项目中使用切片时,我确实会遇到该错误:/@Tyguy7,来自规范:“对于数组或字符串,如果为0,则索引在范围内。此操作的性能如何?我真的希望它不会在引擎盖下创建一个全新的切片。@Tyguy7我认为您试图删除循环中切片的元素。所以你必须小心索引。这很有趣,但并不是真正回答这个问题。这很好,但如果它可以删除数组中唯一的元素会更好。只是a向上看,尝试使用b中的第一个元素(替换为最后一个元素)如果您试图删除切片中的最后一个元素,则显然不起作用。这有助于解释为什么dave上的Mihai的答案为“否”,即使在提到第i个元素时,也指[i+1:]:
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)