为了账号安全,请及时绑定邮箱和手机立即绑定

从 Golang 中的切片中删除

从 Golang 中的切片中删除

Go
精慕HU 2023-06-19 17:46:05
我有以下测试打印原始输入切片(过滤后),没有已删除的元素,但最后有一个额外的元素使输入切片具有相同的长度,即使过滤后它应该是更短。我怎样才能避免有一个“输出切片”?(以正确的方式打印,包含正确的元素,具有预期的长度和容量)为什么我尝试“删除就地”导致“输入切片”的长度与过滤过程之前的长度相同?为什么“输入切片”的长度与我应用过滤过程之前的长度相同?如何进行删除操作以更改“输入切片”的长度?这是代码:这是测试执行的输出:$ go test -v -run TestFoo=== RUN   TestFooOriginal (PRE) slice[{1 FooCat 6.046602879796196} {2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904}]342019/05/31 12:53:30 Loop ID 0Original (POST) slice[{2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904} {3 FooCat 6.645600532184904}]34Filtered element{1 FooCat 6.046602879796196}Output slice[{2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904}]24--- PASS: TestFoo (0.00s)PASSok      git.openenergi.net/scm/flex/service/common  0.008s更新“作为指针的输入切片”好的,假设我想处理原始输入切片,即没有副本或输出切片。为什么以下代码在注释的代码行中引发运行时恐慌?( pointedInSl[inLen-1] = FooItem{})为什么打印的切片(应用函数后)在其末尾包含 2 个相同的项目?如何删除最后一个冗余元素?为什么应用函数后切片的长度仍然与应用函数前的切片长度相同?如何使原始切片缩小 1(即输出长度 = 原始长度 - 1)?
查看完整描述

2 回答

?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

当你有一个int类型的变量时,你想写一个函数来递增它的值,你该怎么做?您要么将指针传递给变量,要么返回必须分配给原始变量的增量值。

例如(在Go Playground上试试):

func inc(i int) int { i++; return i }


var i int = 2

inc(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 = 2

inc(&i)

fmt.Println(i) // This will be 3

切片也是如此。如果您想要/必须修改切片标头(这是一个数据指针、长度和容量,请参阅参考资料reflect.SliceHeader),您要么必须将指针传递给该切片(不是很常见),要么必须返回修改后的新切片您必须在呼叫者处分配的标头。这是更常用的解决方案,这也是内置函数遵循的方法append()

当您切片时,(例如someslice[min:max]),新切片将与原始切片共享支持数组。这意味着如果您修改新切片的元素,原始切片也会观察到这些更改。因此,如果您从新切片中删除一个元素并将元素复制到被删除元素的位置,则原始切片的最后一个元素仍将在那里,它被原始切片“覆盖”。通常的做法是将最后一个元素置零,以便垃圾收集器可以回收它的内存,如果它是指针类型(或“类似”如切片、映射或通道)。

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

正如这个答案中所述:您必须将一个指针传递给您的切片,并修改 中的指向值FindAndRemoveFromFooSlice(),因此您不必返回新切片。

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

你从来没有修改过原始切片,你传递了它所以制作了一个副本,并且在内部FindAndRemoveFromFooSlice()你只能修改副本(但你甚至没有修改副本)。你返回一个新的切片,但你没有分配它,所以原来的切片(头)是完整的。

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

前两个问题回答了这个问题。


查看完整回答
反对 回复 2023-06-19
?
德玛西亚99

TA贡献1770条经验 获得超3个赞

最小工作代码示例(带有注释以提供一些上下文):


// use a pointer for the input slice so then it is changed in-place

func 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

}


查看完整回答
反对 回复 2023-06-19
  • 2 回答
  • 0 关注
  • 182 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号