Loops 有没有一种方法可以迭代一系列整数?
Go的范围可以迭代地图和切片,但我想知道是否有一种方法可以迭代一系列数字,比如:Loops 有没有一种方法可以迭代一系列整数?,loops,go,integer,range,Loops,Go,Integer,Range,Go的范围可以迭代地图和切片,但我想知道是否有一种方法可以迭代一系列数字,比如: for i := range [1..10] { fmt.Println(i) } 或者有并没有一种方法可以像Ruby一样在Go中表示整数的范围?是一个非常小的包,它只是提供了一种语法上不同的方法来迭代整数 for i := range iter.N(4) { fmt.Println(i) } 罗布·派克(Go的作者): 似乎几乎每次有人想办法避免 以惯用的方式做类似于for循环的事情,因为它感
for i := range [1..10] {
fmt.Println(i)
}
或者有并没有一种方法可以像Ruby一样在Go中表示整数的范围?是一个非常小的包,它只是提供了一种语法上不同的方法来迭代整数
for i := range iter.N(4) {
fmt.Println(i)
}
罗布·派克(Go的作者):
似乎几乎每次有人想办法避免
以惯用的方式做类似于for循环的事情,因为它感觉
太长或太麻烦,结果几乎总是更多的击键
而不是应该更短的东西。[…]这就撇开了这些“改进”带来的所有疯狂开销
您可以而且应该只编写for循环。简单、明显的代码就是最好的选择
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
i:=1的
;我这里有一个程序来比较迄今为止提出的两种方法
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()
}
这里是简单的(我已经从清单中删除了非指令)
设置
环路
这是国际热核实验堆
设置
环路
所以你可以看到,国际热核实验堆的解决方案是相当昂贵的,即使它是完全内联在安装阶段。在循环阶段,循环中有一条额外的指令,但这并不太糟糕
我会使用简单的for循环。这里有一个基准来比较Gofor
语句和for子句,以及使用iter
包的Gorange
语句
iter\u测试开始
package main
import (
"testing"
"github.com/bradfitz/iter"
)
const loops = 1e6
func BenchmarkForClause(b *testing.B) {
b.ReportAllocs()
j := 0
for i := 0; i < b.N; i++ {
for j = 0; j < loops; j++ {
j = j
}
}
_ = j
}
func BenchmarkRangeIter(b *testing.B) {
b.ReportAllocs()
j := 0
for i := 0; i < b.N; i++ {
for j = range iter.N(loops) {
j = j
}
}
_ = j
}
// It does not cause any allocations.
func N(n int) []struct{} {
return make([]struct{}, n)
}
func BenchmarkIterAllocs(b *testing.B) {
b.ReportAllocs()
var n []struct{}
for i := 0; i < b.N; i++ {
n = iter.N(loops)
}
_ = n
}
你也可以退房
github.com/wushilin/stream
它是java.util.stream的一个类似惰性流的概念
// It doesn't really allocate the 10 elements.
stream1 := stream.Range(0, 10)
// Print each element.
stream1.Each(print)
// Add 3 to each element, but it is a lazy add.
// You only add when consume the stream
stream2 := stream1.Map(func(i int) int {
return i + 3
})
// Well, this consumes the stream => return sum of stream2.
stream2.Reduce(func(i, j int) int {
return i + j
})
// Create stream with 5 elements
stream3 := stream.Of(1, 2, 3, 4, 5)
// Create stream from array
stream4 := stream.FromArray(arrayInput)
// Filter stream3, keep only elements that is bigger than 2,
// and return the Sum, which is 12
stream3.Filter(func(i int) bool {
return i > 2
}).Sum()
希望这能有所帮助虽然我很同情您对缺少此语言功能的担忧,但您可能只想使用正常的for
循环。当您编写更多的Go代码时,您可能会比您想象的更能接受这一点
我编写了一个简单、惯用的for
循环,该循环返回的值超过chan int
,试图改进中的设计,该设计被指出存在缓存和性能问题,以及一个聪明但奇怪且不直观的实现。我自己的版本的操作方式相同:
package main
import (
"fmt"
"github.com/drgrib/iter"
)
func main() {
for i := range iter.N(10) {
fmt.Println(i)
}
}
然而,基准测试显示,使用渠道是一种非常昂贵的选择。这三种方法的比较,可以从我的包中的iter_test.go
运行,使用
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
在此过程中,该基准还显示了bradfitz
解决方案在循环大小为10
的情况下,与内置的for
子句相比,其表现如何
简言之,到目前为止,似乎还没有办法复制内置的for
子句的性能,同时为[0,n)
提供简单的语法,就像Python和Ruby中的语法一样
这是一个遗憾,因为Go团队可能很容易向编译器添加一个简单的规则来更改这样的行
for i := range 10 {
fmt.Println(i)
}
与i:=0;i<10;i++
相同的机器代码
然而,公平地说,在编写我自己的iter.N
之后(但在对其进行基准测试之前),我回顾了最近编写的一个程序,查看了所有我可以使用它的地方。实际上没有太多。只有一个地方,在我代码的非关键部分,我可以不使用更完整的默认for
子句
因此,虽然从原则上看,这对语言来说可能是一个巨大的失望,但你可能会发现——就像我一样——你实际上并不真正需要它。正如Rob Pike所说的泛型,你可能不会像你想象的那样错过这一功能。马克·米什恩建议使用slice,但在实践中,你可以使用它当通过文字创建的数组可以使用且更短时,e没有理由创建带有
make
的数组,并在中使用for
返回的片段
for i := range [5]int{} {
fmt.Println(i)
}
如果您只想使用and索引或其他任何东西在一个范围内进行迭代,那么这个代码示例对我来说效果很好。不需要额外的声明,也不需要\uu
。不过,我还没有检查性能
for range [N]int{} {
// Body...
}
请注意,在GoLang的第一天。如果这是一个错误的方法,请进行批评。我在GoLang中编写了一个模拟Python范围函数的包:
包装
主程序包
进口(
“fmt”
“github.com/thedevsaddam/iter”
)
func main(){
//顺序:0-9
对于v:=范围iter.N(10){
格式打印F(“%d”,v)
}
fmt.Println()
//输出:01 2 3 4 5 6 7 8 9
//顺序:5-9
对于v:=范围iter.N(5,10){
格式打印F(“%d”,v)
}
fmt.Println()
//产出:56789
//顺序:1-9,增加2
对于v:=范围iter.N(5,10,2){
格式打印F(“%d”,v)
}
fmt.Println()
//产出:579
//顺序:a-e
对于v:=范围iter.L('a','e'){
fmt.Printf(“%s”,字符串(v))
}
fmt.Println()
//输出:a b c d e
}
注意:我写这篇文章是为了好玩!顺便说一句,有时候可能会有帮助
这是一个紧凑、动态的版本,它不依赖于iter(国际热核聚变实验堆)(但工作原理类似):
通过一些调整,size
可以是uint64
(如果需要)类型,但这是要点。问题不在于范围,而在于如何计算片尾。
对于固定的10
for
循环,简单的for
是可以的,但是对于像bfl.size()
这样经过计算的size
循环,每次迭代都会得到一个函数调用。对于int32
来说,简单的range
会有帮助,因为这只会对bfl.size()
进行一次计算
type BFLT PerfServer
func (this *BFLT) Call() {
bfl := MqBufferLCreateTLS(0)
for this.ReadItemExists() {
bfl.AppendU(this.ReadU())
}
this.SendSTART()
// size := bfl.Size()
for i := int32(0); i < bfl.Size() /* size */; i++ {
this.SendU(bfl.IndexGet(i))
}
this.SendRETURN()
}
类型BFLT PerfServer
func(此*BFLT)调用(){
bfl:=MqBufferLCreateTLS(0)
对于此。ReadItemExists(){
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 i := range 10 {
fmt.Println(i)
}
for i := range [5]int{} {
fmt.Println(i)
}
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
for _, num := range nums {
fmt.Println(num, sum)
}
}
for range [N]int{} {
// Body...
}
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)
}
}
type BFLT PerfServer
func (this *BFLT) Call() {
bfl := MqBufferLCreateTLS(0)
for this.ReadItemExists() {
bfl.AppendU(this.ReadU())
}
this.SendSTART()
// size := bfl.Size()
for i := int32(0); i < bfl.Size() /* size */; i++ {
this.SendU(bfl.IndexGet(i))
}
this.SendRETURN()
}