Go的范围可以在地图和切片上迭代,但我想知道是否有一种方法可以在数字范围上迭代,就像这样:

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

或者在Go中是否有一种方法来表示整数的范围,就像Ruby对range类所做的那样?


当前回答

问题不在于范围,而在于如何计算切片的末端。 对于固定的数字10,简单的for循环是可以的,但是对于像bfl.Size()这样的计算大小,你在每次迭代时都得到一个函数调用。大于int32的简单范围会有所帮助,因为这只计算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()
  }

其他回答

问题不在于范围,而在于如何计算切片的末端。 对于固定的数字10,简单的for循环是可以的,但是对于像bfl.Size()这样的计算大小,你在每次迭代时都得到一个函数调用。大于int32的简单范围会有所帮助,因为这只计算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()
  }

以下是一个紧凑的动态版本,不依赖于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类型(如果需要),但这是要点。

Iter是一个非常小的包,只是提供了一种语法上不同的方法来迭代整数。

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

Rob Pike(《围棋》的作者)曾批评过它:

似乎每次都有人想出逃避的办法 用习惯的方式做一个for循环,因为它感觉 太长或太麻烦,结果几乎总是更多的按键 比那个更短的东西。[…这还不考虑这些“改进”带来的所有疯狂的开销。

Go中的惯用方法是这样写一个for循环。

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

在范围上肯定有优势,它们也被用于许多其他语言中,但Go的设计原则是,只有在收益显著超过成本(包括使语言更大的成本)时才引入抽象。理性的人不同意范围的成本和收益,但这个答案是我试图描述我认为的惯用围棋是什么。

下面是一个程序来比较目前建议的两种方法

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循环。