从 Golang 中的切片中删除

我有以下测试打印原始输入切片(过滤后),没有已删除的元素,但最后有一个额外的元素使输入切片具有相同的长度,即使过滤后它应该是更短。

  • 我怎样才能避免有一个“输出切片”?(以正确的方式打印,包含正确的元素,具有预期的长度和容量)

  • 为什么我尝试“删除就地”导致“输入切片”的长度与过滤过程之前的长度相同?

  • 为什么“输入切片”的长度与我应用过滤过程之前的长度相同?如何进行删除操作以更改“输入切片”的长度?

这是代码:

这是测试执行的输出:


$ go test -v -run TestFoo

=== RUN   TestFoo


Original (PRE) slice

[{1 FooCat 6.046602879796196} {2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904}]

3

4

2019/05/31 12:53:30 Loop ID 0


Original (POST) slice

[{2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904} {3 FooCat 6.645600532184904}]

3

4


Filtered element

{1 FooCat 6.046602879796196}


Output slice

[{2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904}]

2

4

--- PASS: TestFoo (0.00s)

PASS

ok      git.openenergi.net/scm/flex/service/common  0.008s

更新“作为指针的输入切片”

好的,假设我想处理原始输入切片,即没有副本或输出切片。

  • 为什么以下代码在注释的代码行中引发运行时恐慌?( pointedInSl[inLen-1] = FooItem{})

  • 为什么打印的切片(应用函数后)在其末尾包含 2 个相同的项目?如何删除最后一个冗余元素?

  • 为什么应用函数后切片的长度仍然与应用函数前的切片长度相同?

  • 如何使原始切片缩小 1(即输出长度 = 原始长度 - 1)?


精慕HU
浏览 183回答 2
2回答

慕田峪7331174

当你有一个int类型的变量时,你想写一个函数来递增它的值,你该怎么做?您要么将指针传递给变量,要么返回必须分配给原始变量的增量值。例如(在Go Playground上试试):func inc(i int) int { i++; return i }var i int = 2inc(i)fmt.Println(i) // This will be 2在上面的代码中,您将i其inc()递增并返回其值。原件i当然不会变,i里面inc()只是一个副本,独立于原件i。要更改原件,您必须评估返回值:i = inc(i)或者首先使用指针(在Go Playground上尝试):func inc(i *int) { *i++ }var i int = 2inc(&i)fmt.Println(i) // This will be 3切片也是如此。如果您想要/必须修改切片标头(这是一个数据指针、长度和容量,请参阅参考资料reflect.SliceHeader),您要么必须将指针传递给该切片(不是很常见),要么必须返回修改后的新切片您必须在呼叫者处分配的标头。这是更常用的解决方案,这也是内置函数遵循的方法append()。当您切片时,(例如someslice[min:max]),新切片将与原始切片共享支持数组。这意味着如果您修改新切片的元素,原始切片也会观察到这些更改。因此,如果您从新切片中删除一个元素并将元素复制到被删除元素的位置,则原始切片的最后一个元素仍将在那里,它被原始切片“覆盖”。通常的做法是将最后一个元素置零,以便垃圾收集器可以回收它的内存,如果它是指针类型(或“类似”如切片、映射或通道)。我怎样才能避免有一个“输出切片”?(以正确的方式打印,包含正确的元素,具有预期的长度和容量)正如这个答案中所述:您必须将一个指针传递给您的切片,并修改 中的指向值FindAndRemoveFromFooSlice(),因此您不必返回新切片。为什么我尝试“删除就地”导致“输入切片”的长度与过滤过程之前的长度相同?你从来没有修改过原始切片,你传递了它所以制作了一个副本,并且在内部FindAndRemoveFromFooSlice()你只能修改副本(但你甚至没有修改副本)。你返回一个新的切片,但你没有分配它,所以原来的切片(头)是完整的。为什么“输入切片”的长度与我应用过滤过程之前的长度相同?如何进行删除操作以更改“输入切片”的长度?前两个问题回答了这个问题。

德玛西亚99

最小工作代码示例(带有注释以提供一些上下文):// use a pointer for the input slice so then it is changed in-placefunc FindAndRemoveFromFooSliceInPlace(iFilter int, inSl *[]FooItem) *FooItem {    pointedInSl := *inSl // dereference the pointer so then we can use `append`    inLen := len(pointedInSl)    for idx, elem := range pointedInSl {        if elem.Id == iFilter {            log.Printf("Loop ID %v", idx)            // check these docs: https://github.com/golang/go/wiki/SliceTricks#delete            pointedInSl = append(pointedInSl[:idx], pointedInSl[idx+1:inLen]...)            pointedInSl = pointedInSl[:inLen-1]            *inSl = pointedInSl // assigning the new slice to the pointed value before returning            return &elem        }    }    return nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go