“声明但未使用”是因为Go编译器无法考虑循环吗?

huangapple go评论73阅读模式
英文:

'declared and not used' because Go compiler can't consider loops?

问题

标题不好,但我不知道如何在字符限制内以其他方式描述它。

作为一个学习练习,我正在尝试编写一个小的Go程序来模拟彩票抽奖。它会抽取六个随机数作为中奖号码,然后不断地抽取随机的整数数组,直到再次抽到中奖号码为止。

首先,我编写了一个函数,该函数接受一个通道,并无限循环地将“包含6个随机整数的数组”添加到通道中:

func draw(ch chan<- [6]int) {
    generator := rand.New(rand.NewSource(time.Now().UnixNano()))
    for {
        ch <- [6]int{
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
        }
    }
}

然后在main()函数中,我指定了两个操作系统线程,创建了一个可以容纳250个包含6个整数的数组的通道,并在一个goroutine中启动了我的draw()函数。

runtime.GOMAXPROCS(2)
ch := make(chan [6]int, 250)
go draw(ch)

接下来,我从通道中获取一个中奖号码(例如[4 8 15 16 23 42]),然后获取一个“当前”号码,即最近一次抽奖的号码。我将游戏次数计数器设置为1:

winning := <- ch
current := <- ch
games_played := 1

这里是棘手的部分。

在一个无限循环中,我检查当前抽奖号码是否等于中奖号码。如果是,我打印出游戏次数,并跳出循环。

如果不是,我将current设置为一个新的抽奖号码,并增加计数器。然后,循环应该再次运行if winning == current...的检查,直到找到匹配为止。

for {
    if winning == current {
        fmt.Println(games_played)
        break
    } else {
        current := <- ch
        games_played += 1
    }
}

问题在于:倒数第四行的current := <- ch会引发编译错误,错误信息为“current被声明但未使用”。我想说:“是的,我知道在该点向下读取后它不再使用,但它在循环内部声明,所以它的值在下一次迭代中是重要的。”但我无法弄清楚如何解决这个问题,或者是否犯了什么愚蠢的错误。显然,我对Go一无所知。但是对我来说,经过思考,逻辑是正确的。我是不是搞错了什么?

(注意:我知道忽略了一个问题,即抽取的号码[1 2 3][2 3 1]不相等,现在先忽略这个问题。)

英文:

Poor title, but I didn't know how else to describe it within the character limit.

As a learning exercise, I'm trying to write a little Go program that simulates a lottery draw. It draws six random numbers to be the winning set, then continually draws random arrays of random ints until you get that set again.

First I wrote a function which takes a channel and infinitely loops "add array of 6 random ints to the channel":

func draw(ch chan&lt;- [6]int) {
    generator := rand.New(rand.NewSource(time.Now().UnixNano()))
    for {
        ch &lt;- [6]int{
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
            generator.Intn(100),
        }
    }
}

Then in main() I specify two OS threads, create a channel that can hold 250 arrays of 6 ints, and start my draw() function in a goroutine.

runtime.GOMAXPROCS(2)
ch := make(chan [6]int, 250)
go draw(ch)

Next I take a winning set (eg [4 8 15 16 23 42]) from the channel, then a 'current' set, meaning the most recent draw. I set my game_played counter to 1:

winning := &lt;- ch
current := &lt;- ch
games_played := 1

Here's the tricky bit.

In an infinite loop, I check if the current draw is equal to the winning draw. If it is, I print the number of games played, and break from the loop.

If it isn't, I set current to a new draw, and increment the counter. The loop should then run the if winning == current... check again over and over until there's a match.

for {
    if winning == current {
        fmt.Println(games_played)
        break
    } else {
        current := &lt;- ch
        games_played += 1
    }
}

Here's the problem: that fourth-last line, current := &lt;- ch, throws a compiler error, 'current declared and not used'. I want to say "Yeah, I know it's not used after that point reading downward, but it's declared inside a loop, so its value matters on the next iteration." But I can't work out how, or if I've done something stupid. I'm totally clueless about Go, obviously. But to me, thinking through it, the logic is sound. Am I messing something up?

(Note: I'm aware of the oversight that a draw of [1 2 3] won't be equal to [2 3 1], ignoring that for now.)

答案1

得分: 6

第二个current变量在if作用域中。将current := &lt;- ch替换为current = &lt;- ch(没有冒号)。使用:=会在嵌套作用域中定义一个新的current变量。

if winning == current {
    fmt.Println(games_played)
    break
} else {
    current := &lt;- ch
    games_played += 1
}

等同于:

if winning == current {
    fmt.Println(games_played)
    break
} else {
    var current int[6] // 你不想要这个,因为它会遮蔽外部作用域中的current
    current = &lt;- ch // 你只想要这个
    games_played += 1
}
英文:

The second current is in the if scope. Replace current := &lt;- ch with current = &lt;- ch (no colon). When using := you define a new current variable in the nested scope.

if winning == current {
    fmt.Println(games_played)
    break
} else {
    current := &lt;- ch
    games_played += 1
}

is equivalent of:

if winning == current {
    fmt.Println(games_played)
    break
} else {
    var current int[6] // you don&#39;t want this, as it shadows your
                       // current form the outher scope
    current = &lt;- ch // you want only this guy
    games_played += 1
}

huangapple
  • 本文由 发表于 2016年1月25日 23:08:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/34995808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定