Go的范围可以在地图和切片上迭代,但我想知道是否有一种方法可以在数字范围上迭代,就像这样:
for i := range [1..10] {
fmt.Println(i)
}
或者在Go中是否有一种方法来表示整数的范围,就像Ruby对range类所做的那样?
Go的范围可以在地图和切片上迭代,但我想知道是否有一种方法可以在数字范围上迭代,就像这样:
for i := range [1..10] {
fmt.Println(i)
}
或者在Go中是否有一种方法来表示整数的范围,就像Ruby对range类所做的那样?
当前回答
如果你只是想在一个w/o范围内使用和索引或其他东西进行迭代,这个代码样本对我来说很好。不需要额外的声明,没有_。不过,还没有检查性能。
for range [N]int{} {
// Body...
}
附注:在戈朗的第一天。如果这是一种错误的方法,请进行批评。
其他回答
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
for _, num := range nums {
fmt.Println(num, sum)
}
}
虽然我很同情您对缺少这个语言特性的担忧,但您可能只想使用普通的for循环。当你编写更多的Go代码时,你可能会比你想象的更能接受这一点。
我编写了这个iter包——它由一个简单的、习惯的for循环支持,该循环通过chan int返回值——试图改进https://github.com/bradfitz/iter中的设计,该设计已被指出存在缓存和性能问题,以及一个聪明但奇怪且不直观的实现。我自己的版本也是这样:
package main
import (
"fmt"
"github.com/drgrib/iter"
)
func main() {
for i := range iter.N(10) {
fmt.Println(i)
}
}
然而,基准测试显示,使用通道是一个非常昂贵的选择。可以从iter_test运行的3个方法的比较。放进我的包里
go test -bench=. -run=.
量化了它的表现有多差
BenchmarkForMany-4 5000 329956 ns/op 0 B/op 0 allocs/op
BenchmarkDrgribIterMany-4 5 229904527 ns/op 195 B/op 1 allocs/op
BenchmarkBradfitzIterMany-4 5000 337952 ns/op 0 B/op 0 allocs/op
BenchmarkFor10-4 500000000 3.27 ns/op 0 B/op 0 allocs/op
BenchmarkDrgribIter10-4 500000 2907 ns/op 96 B/op 1 allocs/op
BenchmarkBradfitzIter10-4 100000000 12.1 ns/op 0 B/op 0 allocs/op
在这个过程中,这个基准测试还显示了与内置的for子句相比,对于大小为10的循环,bradfitz解决方案的性能如何不佳。
简而言之,到目前为止,似乎还没有发现一种方法可以复制内置for子句的性能,同时为[0,n)提供一种简单的语法,就像在Python和Ruby中发现的那样。
这是一个遗憾,因为Go团队可能很容易向编译器添加一个简单的规则来更改一行,如
for i := range 10 {
fmt.Println(i)
}
与I:= 0相同的机器代码;I < 10;我+ +。
然而,公平地说,在我自己写完iter之后。N(但在对其进行基准测试之前),我回顾了最近编写的程序,以查看所有可以使用它的地方。实际上并不多。在我的代码的非重要部分中,只有一个地方不需要使用更完整的default for子句。
因此,虽然从原则上看,这对语言来说是一个巨大的失望,但您可能会发现——就像我所做的那样——实际上在实践中并不真正需要它。就像Rob Pike所说的泛型一样,您可能不会像您想象的那样想念这个特性。
我用Golang写了一个包,它模仿了Python的range函数:
包https://github.com/thedevsaddam/iter
package main
import (
"fmt"
"github.com/thedevsaddam/iter"
)
func main() {
// sequence: 0-9
for v := range iter.N(10) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 0 1 2 3 4 5 6 7 8 9
// sequence: 5-9
for v := range iter.N(5, 10) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 5 6 7 8 9
// sequence: 1-9, increment by 2
for v := range iter.N(5, 10, 2) {
fmt.Printf("%d ", v)
}
fmt.Println()
// output: 5 7 9
// sequence: a-e
for v := range iter.L('a', 'e') {
fmt.Printf("%s ", string(v))
}
fmt.Println()
// output: a b c d e
}
注意:我只是为了好玩才写的!顺便说一下,有时候可能会有帮助
以下是一个紧凑的动态版本,不依赖于iter(但工作方式类似):
package main
import (
"fmt"
)
// N is an alias for an unallocated struct
func N(size int) []struct{} {
return make([]struct{}, size)
}
func main() {
size := 1000
for i := range N(size) {
fmt.Println(i)
}
}
通过一些调整,大小可以是uint64类型(如果需要),但这是要点。
下面是一个程序来比较目前建议的两种方法
import (
"fmt"
"github.com/bradfitz/iter"
)
func p(i int) {
fmt.Println(i)
}
func plain() {
for i := 0; i < 10; i++ {
p(i)
}
}
func with_iter() {
for i := range iter.N(10) {
p(i)
}
}
func main() {
plain()
with_iter()
}
像这样编译以生成反汇编
go build -gcflags -S iter.go
这里是简单的(我已经从清单中删除了非指令)
设置
0035 (/home/ncw/Go/iter.go:14) MOVQ $0,AX
0036 (/home/ncw/Go/iter.go:14) JMP ,38
loop
0037 (/home/ncw/Go/iter.go:14) INCQ ,AX
0038 (/home/ncw/Go/iter.go:14) CMPQ AX,$10
0039 (/home/ncw/Go/iter.go:14) JGE $0,45
0040 (/home/ncw/Go/iter.go:15) MOVQ AX,i+-8(SP)
0041 (/home/ncw/Go/iter.go:15) MOVQ AX,(SP)
0042 (/home/ncw/Go/iter.go:15) CALL ,p+0(SB)
0043 (/home/ncw/Go/iter.go:15) MOVQ i+-8(SP),AX
0044 (/home/ncw/Go/iter.go:14) JMP ,37
0045 (/home/ncw/Go/iter.go:17) RET ,
这里是with_iter
设置
0052 (/home/ncw/Go/iter.go:20) MOVQ $10,AX
0053 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-24(SP)
0054 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-16(SP)
0055 (/home/ncw/Go/iter.go:20) MOVQ $0,~r0+-8(SP)
0056 (/home/ncw/Go/iter.go:20) MOVQ $type.[]struct {}+0(SB),(SP)
0057 (/home/ncw/Go/iter.go:20) MOVQ AX,8(SP)
0058 (/home/ncw/Go/iter.go:20) MOVQ AX,16(SP)
0059 (/home/ncw/Go/iter.go:20) PCDATA $0,$48
0060 (/home/ncw/Go/iter.go:20) CALL ,runtime.makeslice+0(SB)
0061 (/home/ncw/Go/iter.go:20) PCDATA $0,$-1
0062 (/home/ncw/Go/iter.go:20) MOVQ 24(SP),DX
0063 (/home/ncw/Go/iter.go:20) MOVQ 32(SP),CX
0064 (/home/ncw/Go/iter.go:20) MOVQ 40(SP),AX
0065 (/home/ncw/Go/iter.go:20) MOVQ DX,~r0+-24(SP)
0066 (/home/ncw/Go/iter.go:20) MOVQ CX,~r0+-16(SP)
0067 (/home/ncw/Go/iter.go:20) MOVQ AX,~r0+-8(SP)
0068 (/home/ncw/Go/iter.go:20) MOVQ $0,AX
0069 (/home/ncw/Go/iter.go:20) LEAQ ~r0+-24(SP),BX
0070 (/home/ncw/Go/iter.go:20) MOVQ 8(BX),BP
0071 (/home/ncw/Go/iter.go:20) MOVQ BP,autotmp_0006+-32(SP)
0072 (/home/ncw/Go/iter.go:20) JMP ,74
loop
0073 (/home/ncw/Go/iter.go:20) INCQ ,AX
0074 (/home/ncw/Go/iter.go:20) MOVQ autotmp_0006+-32(SP),BP
0075 (/home/ncw/Go/iter.go:20) CMPQ AX,BP
0076 (/home/ncw/Go/iter.go:20) JGE $0,82
0077 (/home/ncw/Go/iter.go:20) MOVQ AX,autotmp_0005+-40(SP)
0078 (/home/ncw/Go/iter.go:21) MOVQ AX,(SP)
0079 (/home/ncw/Go/iter.go:21) CALL ,p+0(SB)
0080 (/home/ncw/Go/iter.go:21) MOVQ autotmp_0005+-40(SP),AX
0081 (/home/ncw/Go/iter.go:20) JMP ,73
0082 (/home/ncw/Go/iter.go:23) RET ,
所以你可以看到iter解决方案是相当昂贵的,即使它是完全内联在设置阶段。在循环阶段,循环中有一个额外的指令,但这并不太糟糕。
我会使用简单的for循环。