- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我有以下测试打印原始输入 slice (过滤后),没有已删除的元素,但在末尾有一个额外的元素使输入 slice 具有相同的长度,即使在过滤之后它应该更短。
我已经阅读了这个文档 https://github.com/golang/go/wiki/SliceTricks#delete然而,我认为我遗漏了一些关于 Go 的陷阱,因为我似乎以错误的方式使用 slice 。
这是代码:
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
关于“输入 slice 作为指针”的更新
好的,假设我想处理原始输入 slice ,即没有副本或输出 slice 。
pointedInSl[inLen-1] = FooItem{}
)这是代码:
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
最佳答案
当你有一个 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
当然不会变,inc()
里面的i
只是一个副本,独立于原来的i
。要更改原始值,您必须评估返回值:
i = inc(i)
或者首先使用指针(在 Go Playground 上尝试):
func inc(i *int) { *i++ }
var i int = 2
inc(&i)
fmt.Println(i) // This will be 3
slice 也是如此。如果你想/必须修改 slice 头(这是一个数据指针、长度和容量,参见 reflect.SliceHeader
),你要么必须传递一个指向该 slice 的指针(不是很常见),要么必须返回修改后的,您必须在调用者处分配的新 slice header 。这是更常用的解决方案,这是内置的方法 append()
也跟着。
当您 slice 时,(例如 someslice[min:max]
),新 slice 将与原始 slice 共享支持数组。这意味着如果您修改新 slice 的元素,原始 slice 也会观察到这些变化。因此,如果您从新 slice 中删除一个元素并将元素复制到被删除元素的位置,则原始 slice 的最后一个元素仍将在那里,它被原始 slice “覆盖”。通常的做法是将最后一个元素置零,以便垃圾收集器可以回收它的内存,如果它是指针类型(或“类似”如 slice 、映射或 channel )。有关详细信息,请参阅 Memory leak in golang slice和 Does go garbage collect parts of slices?
直接回答您的问题:
- how can I avoid to have an "output slice"? (which is printed in the correct way, containing the right elements, having the expected length and capacity)
如本回答所述:您必须将指针传递给您的 slice ,并在 FindAndRemoveFromFooSlice()
中修改指向的值,因此您不必返回新 slice 。
- why my attempt at "removing inplace" leads to having the "input slice" with the same length as it had before the filtering process?
您从未修改过原始 slice ,您传递了它以便创建一个副本,而在 FindAndRemoveFromFooSlice()
中您只能修改副本(但您甚至没有修改副本)。你返回一个新的 slice ,但你没有分配它,所以原始 slice (头)是完整的。
- why the "input slice" has the same length as before I was applying the filtering process? How can I make the remove operation to change the length of the "input slice"?
前两个问题已经回答了这一点。
查看相关问题:
关于loops - 从 Golang 中的 slice 中删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56394632/
我认为这样的表达式会导致 Haskell 永远评估。但是 GHCi 和编译程序中的行为让我感到惊讶。 例如,在 GHCi 中,这些表达式一直阻塞到 I Control+C ,但不消耗 CPU。看起来像
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
如果可以的话,我想减少这段代码: class Alarm { internal static void isGreaterThanOrBelowValue(int min, int max,
我有以下问题: 我想创建一个批处理文件,循环访问一定数量的 IP 地址,以停止远程 PC 上的某个服务。 因为停止过程需要一些时间,所以我需要第二个循环来查询服务的状态并等待,直到服务达到“已停止”状
我已经完整地编写了“The Rust Programming Language”在线书籍中的程序,chapter 2 .我还进一步开发了它:通过添加一个简单的问题/响应,用户可以通过输入“y”再次玩游
这个人已经困扰了我一阵子了, 我们应该如何在集合中存储值或在for循环中映射? (let [s #{}] (for [ i (range 10) j (range 1
mov ecx, 16 looptop: . . . loop looptop 这个循环会执行多少次? 如果 ecx
我似乎无法找到一种在 Xtend 中表达以下内容而不诉诸 while 循环的好方法: for(int i = 0; i range(int stop) { range(0, stop) }
好吧,长话短说,我正在学习汇编,我正在尝试循环打印出 ascii 字符“0”-“9”。因此,我完成了我在示例中看到的所有基础知识,例如使用 pushad 和 popad 保存寄存器状态,分配堆栈空间,
我正在尝试为自己编写一个扑克计算器,我有一个 5 级深的 for 循环。 为此,我将 for 循环一个接一个地嵌套。我正在寻找一种方法来简单地使用一个循环(或函数),它可以告诉我想去多少层。对于这个例
我有一本包含约 150,000 个键的字典。没有重复的键。每个 key 的长度为 127 个字符,每个 key 在 1-11 个位置上有所不同(大多数差异发生在 key 的末尾)。每个键的值是一个唯一
我正在尝试编写一个 Lisp 程序来实现与点和方 block 非常相似的棋盘游戏,这意味着我有两个玩家相互竞争但可以连续移动。我正在尝试实现最简单的 minimax 算法来实现这一点,没有 alpha
下面是我实现的代码的简要说明。 for 循环的复杂度应该是 O(n)。我只是无法弄清楚内部 while 循环的时间复杂度。 int x,n; // Inputted by the user.
我目前正在尝试使用 html 分词器 https://godoc.org/golang.org/x/net/html . 所以我想做的是:从 url 获取所有链接,如果 url 包含特定字符串 ->
我有 32 个文件(以相同的模式命名,唯一的区别是下面写的 $sample 编号)我想分成 4 个文件夹。我正在尝试使用以下脚本来完成这项工作,但该脚本无法正常工作,有人可以帮我使用以下 shell
我必须根据 where 条件在我的内部表上做一个循环,但根据我的程序模式,必须在运行时修改 where 条件的字段。 我知道在 SELECT 语句中这是可能的,但是当我在循环中执行此操作时出现错误。
我正在学习关于kdb数据库的q。我担心q中没有循环。 我需要写一个算法,用像C这样的冗长程序在几个嵌套的for循环中编写。但是在q中,我被无法循环的事实所困扰。 仅举一个具体的例子(很多),我有一个简
我不明白为什么这段代码只循环一次然后退出? 在 Ghci 中,我只能回答第一个循环,然后似乎变量 cont 设置为 false 并且我没有提示回答。 结果是: *Main> testLoop1 td1
我正在 Racket 中运行 for 循环,对于列表中的每个对象,我想执行两件事:如果该项目满足条件,(1) 将其附加到我的新列表中,(2) 然后打印列表。但我不知道如何在 Racket 中执行此操作
我正在尝试使用 matlab 并行包中的 parfor 循环。我和这个人有类似的问题:MATLAB parfor slicing issue? 。输出矩阵似乎没有被识别为切片变量。在我的具体情况下,我
我是一名优秀的程序员,十分优秀!