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

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

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


当前回答

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

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

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

其他回答

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

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

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

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

虽然我很同情您对缺少这个语言特性的担忧,但您可能只想使用普通的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所说的泛型一样,您可能不会像您想象的那样想念这个特性。

如果你只是想在一个w/o范围内使用和索引或其他东西进行迭代,这个代码样本对我来说很好。不需要额外的声明,没有_。不过,还没有检查性能。

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

附注:在戈朗的第一天。如果这是一种错误的方法,请进行批评。

Mark Mishyn建议使用slice,但是没有理由使用make和use in来创建数组,因为通过literal创建的数组可以被使用,而且它更短

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