dscdttg4389
2014-02-22 05:39
浏览 49
已采纳

有没有办法在Golang中迭代整数范围?

Golang's range can iterate over maps and slices, but I was wondering if there is a way to iterate over a range of numbers, something like this

for i := range [1..10] {
    fmt.Println(i)
}

or is there a way to represent range of integers in Go like how ruby does?

图片转代码服务由CSDN问答提供 功能建议

Golang的范围可以遍历地图和切片,但是我想知道是否有一种方法可以遍历 数字,诸如此类

  for i:= range [1..10] {
 fmt.Println(i)
} 
   
 
 

,或者像ruby一样,有没有办法在Go中表示整数范围?

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

9条回答 默认 最新

  • donglan7594 2014-02-22 07:15
    已采纳

    You can, and should, just write a for loop. Simple, obvious code is the Go way.

    for i := 1; i <= 10; i++ {
        fmt.Println(i)
    }
    
    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • dongre1907 2014-02-22 05:44

    iter is a very small package that just provides a syntantically different way to iterate over integers.

    for i := range iter.N(4) {
        fmt.Println(i)
    }
    

    Rob Pike (an author of Go) has criticized it:

    It seems that almost every time someone comes up with a way to avoid doing something like a for loop the idiomatic way, because it feels too long or cumbersome, the result is almost always more keystrokes than the thing that is supposedly shorter. [...] That's leaving aside all the crazy overhead these "improvements" bring.

    评论
    解决 无用
    打赏 举报
  • douyi3767 2014-02-22 08:50

    Here is a program to compare the two ways suggested so far

    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()
    }
    

    Compile like this to generate disassembly

    go build -gcflags -S iter.go
    

    Here is plain (I've removed the non instructions from the listing)

    setup

    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     ,
    

    And here is with_iter

    setup

    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     ,
    

    So you can see that the iter solution is considerably more expensive even though it is fully inlined in the setup phase. In the loop phase there is an extra instruction in the loop, but it isn't too bad.

    I'd use the simple for loop.

    评论
    解决 无用
    打赏 举报
  • donglang2010 2014-02-22 18:23

    Here's a benchmark to compare a Go for statement with a ForClause and a Go range statement using the iter package.

    iter_test.go

    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
    }
    

    Output:

    $ go test -bench=. -run=.
    testing: warning: no tests to run
    PASS
    BenchmarkForClause      2000       1260356 ns/op           0 B/op          0 allocs/op
    BenchmarkRangeIter      2000       1257312 ns/op           0 B/op          0 allocs/op
    BenchmarkIterAllocs 20000000            82.2 ns/op         0 B/op          0 allocs/op
    ok      so/test 7.026s
    $
    
    评论
    解决 无用
    打赏 举报
  • doufei8691 2015-10-02 06:50

    You can also check out github.com/wushilin/stream

    It is a lazy stream like concept of 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()
    

    Hope this helps

    评论
    解决 无用
    打赏 举报
  • donglefu6195 2017-04-03 18:54

    While I commiserate with your concern about lacking this language feature, you're probably just going to want to use a normal for loop. And you'll probably be more okay with that than you think as you write more Go code.

    I wrote this iter package — which is backed by a simple, idiomatic for loop that returns values over a chan int — in an attempt to improve on the design found in https://github.com/bradfitz/iter, which has been pointed out to have caching and performance issues, as well as a clever, but strange and unintuitive implementation. My own version operates the same way:

    package main
    
    import (
        "fmt"
        "github.com/drgrib/iter"
    )
    
    func main() {
        for i := range iter.N(10) {
            fmt.Println(i)
        }
    }
    

    However, benchmarking revealed that the use of a channel was a very expensive option. The comparison of the 3 methods, which can be run from iter_test.go in my package using

    go test -bench=. -run=.
    

    quantifies just how poor its performance is

    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
    

    In the process, this benchmark also shows how the bradfitz solution underperforms in comparison to the built-in for clause for a loop size of 10.

    In short, there appears to be no way discovered so far to duplicate the performance of the built-in for clause while providing a simple syntax for [0,n) like the one found in Python and Ruby.

    Which is a shame because it would probably be easy for the Go team to add a simple rule to the compiler to change a line like

    for i := range 10 {
        fmt.Println(i)
    }
    

    to the same machine code as for i := 0; i < 10; i++.

    However, to be fair, after writing my own iter.N (but before benchmarking it), I went back through a recently written program to see all the places I could use it. There actually weren't many. There was only one spot, in a non-vital section of my code, where I could get by without the more complete, default for clause.

    So while it may look like this is a huge disappointment for the language in principle, you may find — like I did — that you actually don't really need it in practice. Like Rob Pike is known to say for generics, you might not actually miss this feature as much as you think you will.

    评论
    解决 无用
    打赏 举报
  • drsqpko5286 2017-12-07 21:34

    It was suggested by Mark Mishyn to use slice but there is no reason to create array with make and use in for returned slice of it when array created via literal can be used and it's shorter

    for i := range [5]int{} {
            fmt.Println(i)
    }
    
    评论
    解决 无用
    打赏 举报
  • douzachan4578 2018-07-26 02:49
    package main
    
    import "fmt"
    
    func main() {
    
        nums := []int{2, 3, 4}
        for _, num := range nums {
           fmt.Println(num, sum)    
        }
    }
    
    评论
    解决 无用
    打赏 举报
  • doumi9661 2019-07-30 03:51

    If you want to just iterate over a range w/o using and indices or anything else, this code sample worked just fine for me. No extra declaration needed, no _. Haven't checked the performance, though.

    for range [N]int{} {
        // Body...
    }
    

    P.S. The very first day in GoLang. Please, do critique if it's a wrong approach.

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题