【发布时间】:2019-10-17 01:50:31
【问题描述】:
我有以下测试正在打印原始输入切片(过滤后),但没有删除已删除的元素,但最后有一个额外元素使输入切片的长度相同,即使在过滤后也是如此它应该更短。
我已经浏览了这个文档https://github.com/golang/go/wiki/SliceTricks#delete 但是我认为我错过了一些关于 Go 的陷阱,因为我似乎使用了错误的方法来使用切片。
- 如何避免出现“输出切片”? (以正确的方式打印,包含正确的元素,具有预期的长度和容量)
- 为什么我尝试“移除就地”会导致“输入切片”的长度与过滤过程之前的长度相同?
- 为什么“输入切片”的长度与我应用过滤过程之前的长度相同?如何进行删除操作以更改“输入切片”的长度?
这是代码:
package foo
import (
"fmt"
"log"
"math/rand"
"testing"
)
type FooItem struct {
Id int
Category string
Value float64
}
const minRand = 0
const maxRand = 10
const maxSliceLen = 3
var inFooSlice []FooItem
func init() {
for i := 1; i <= maxSliceLen; i++ {
inFooSlice = append(inFooSlice, FooItem{
Id: i,
Category: "FooCat",
Value: minRand + rand.Float64()*(maxRand-minRand),
})
}
}
// this is the function I am testing
func FindAndRemoveFromFooSlice(iFilter int, inSl []FooItem) (*FooItem, []FooItem) {
inLen := len(inSl)
outSl := make([]FooItem, inLen)
for idx, elem := range inSl {
if elem.Id == iFilter {
log.Printf("Loop ID %v", idx)
// check these docs: https://github.com/golang/go/wiki/SliceTricks#delete
outSl = inSl[:idx+copy(inSl[idx:], inSl[idx+1:inLen])]
outSl = outSl[:inLen-1]
return &elem, outSl
}
}
return nil, nil
}
func TestFoo(t *testing.T) {
fmt.Printf("\nOriginal (PRE) slice\n")
fmt.Println(inFooSlice)
fmt.Println(len(inFooSlice))
fmt.Println(cap(inFooSlice))
idFilter := 1
fePtr, outFooSlice := FindAndRemoveFromFooSlice(idFilter, inFooSlice)
fmt.Printf("\nOriginal (POST) slice\n")
fmt.Println(inFooSlice)
fmt.Println(len(inFooSlice))
fmt.Println(cap(inFooSlice))
fmt.Printf("\nFiltered element\n")
fmt.Println(*fePtr)
fmt.Printf("\nOutput slice\n")
fmt.Println(outFooSlice)
fmt.Println(len(outFooSlice))
fmt.Println(cap(outFooSlice))
}
这是测试执行的输出:
$ 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)?
这是代码:
func FindAndRemoveFromFooSliceInPlace(iFilter int, inSl *[]FooItem) *FooItem {
pointedInSl := *inSl
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[inLen-1] = FooItem{} // why this throws a runtime "panic: runtime error: index out of range" ???
pointedInSl = pointedInSl[:inLen-1]
return &elem
}
}
return nil
}
func TestFooInPlace(t *testing.T) {
fmt.Printf("\nOriginal (PRE) slice\n")
fmt.Println(inFooSlice)
fmt.Println(len(inFooSlice))
fmt.Println(cap(inFooSlice))
idFilter := 1
fePtr := FindAndRemoveFromFooSliceInPlace(idFilter, &inFooSlice)
fmt.Printf("\nOriginal (POST) slice\n")
fmt.Println(inFooSlice)
fmt.Println(len(inFooSlice))
fmt.Println(cap(inFooSlice))
fmt.Printf("\nFiltered element\n")
fmt.Println(*fePtr)
}
这是奇怪的输出:
$ go test -v -run TestFooInPlace
=== RUN TestFooInPlace
Original (PRE) slice
[{1 FooCat 6.046602879796196} {2 FooCat 9.405090880450125} {3 FooCat 6.645600532184904}]
3
4
2019/05/31 16:32:38 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}
--- PASS: TestFooInPlace (0.00s)
PASS
ok git.openenergi.net/scm/flex/service/common 0.007s
【问题讨论】: