这看起来有点奇怪,但这里的大多数答案都是危险的,并且掩盖了他们实际在做什么。查看关于从切片中删除项目的原始问题,正在制作切片的副本,然后将其填充。这可以确保当切片在程序中传递时不会引入细微的错误。
下面是一些代码,比较用户在此线程中的答案和原始帖子。这是一个可以在其中乱搞此代码的go 游乐场。
基于附加的删除
package main
import (
    "fmt"
)
func RemoveIndex(s []int, index int) []int {
    return append(s[:index], s[index+1:]...)
}
func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)
    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]
    removeIndex[0] = 999
    fmt.Println("all: ", all) //[999 1 2 3 4 6 7 9 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}
在上面的示例中,您可以看到我创建了一个切片并手动用数字 0 到 9 填充它。然后我们从所有切片中删除索引 5 并将其指定为删除索引。然而,当我们现在打印出所有内容时,我们发现它也已被修改。这是因为切片是指向底层数组的指针。将其写出也会removeIndex导致all被修改,区别在于,all有一个元素不再可以从 访问removeIndex。接下来我们更改一个值removeIndex,我们可以看到all它也被修改了。《Effective go》对此进行了更详细的介绍。
我不会详细介绍下面的示例,但它对我们的目的做了同样的事情。这只是说明使用副本没有什么不同。
package main
import (
    "fmt"
)
func RemoveCopy(slice []int, i int) []int {
    copy(slice[i:], slice[i+1:])
    return slice[:len(slice)-1]
}
func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeCopy := RemoveCopy(all, 5)
    fmt.Println("all: ", all) //[0 1 2 3 4 6 7 8 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[0 1 2 3 4 6 7 8 9]
    removeCopy[0] = 999
    fmt.Println("all: ", all) //[99 1 2 3 4 6 7 9 9]
    fmt.Println("removeCopy: ", removeCopy) //[999 1 2 3 4 6 7 8 9]
}
问题原答案
查看原始问题,它不会修改从中删除项目的切片。对于大多数访问此页面的人来说,使该线程中的原始答案成为迄今为止最好的答案。
package main
import (
    "fmt"
)
func OriginalRemoveIndex(arr []int, pos int) []int {
    new_arr := make([]int, (len(arr) - 1))
    k := 0
    for i := 0; i < (len(arr) - 1); {
        if i != pos {
            new_arr[i] = arr[k]
            k++
        } else {
            k++
        }
        i++
    }
    return new_arr
}
func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    originalRemove := OriginalRemoveIndex(all, 5)
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[0 1 2 3 4 6 7 8 9]
    originalRemove[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("originalRemove: ", originalRemove) //[999 1 2 3 4 6 7 8 9]
}
正如您所看到的,此输出符合大多数人的预期,也可能是大多数人想要的。的修改originalRemove不会引起变化,all删除索引并分配索引的操作也不会引起变化!极好的!
这段代码有点长,所以上面的内容可以改为这样。
正确答案
package main
import (
    "fmt"
)
func RemoveIndex(s []int, index int) []int {
    ret := make([]int, 0)
    ret = append(ret, s[:index]...)
    return append(ret, s[index+1:]...)
}
func main() {
    all := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    removeIndex := RemoveIndex(all, 5)
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("removeIndex: ", removeIndex) //[0 1 2 3 4 6 7 8 9]
    removeIndex[0] = 999
    fmt.Println("all: ", all) //[0 1 2 3 4 5 6 7 8 9]
    fmt.Println("removeIndex: ", removeIndex) //[999 1 2 3 4 6 7 8 9]
}
与原始的删除索引解决方案几乎相同,但是我们在返回之前创建了一个新切片来附加。