2

ポーリング時に値を返す関数がありますが、以下に示すように、ある時点で適切な値を返さなくなります。

if !ok毎回チェックするよりも、ポーリングする慣用的な方法はありますか。でチャンネルをポーリングするようなことを考えていrangeます。

package main

import "fmt"

func iter() func() (int, bool) {
    i := 0
        return func() (int, bool) {
        if i < 10 {
            i++
            return i, true
        }
        return i, false
    }
}

func main() {
    f := iter()
    for {
        v, ok := f()
        if !ok {
            break
        }
        fmt.Println(v)
    }
}
4

2 に答える 2

6

OK のチェックを回避する方法はないと思いますが、醜いブレークを回避するために再構築することができます。

for v,ok := f(); ok; v,ok = f() {
    fmt.Println(v)
}

これは、次のいずれかの場合にのみ機能することに注意してください。

  1. チェックする複数の戻り値を持つ単一の関数がある、または

  2. チェックする戻り値が 1 つだけの関数が 1 つ以上ある

残念ながら、Go では次のようなことはできません。

f := iter()
g := iter()
v,ok,v2,ok2 := f(), g(); ok && ok2; v,ok,v2,ok2 := f(), g() {
   // code
}

したがって、複数の関数を使用するケースがある場合、単一の値のみを返さない限り、ifs と break に固執します。

そうは言っても(そして振り返ってみると)、Goでイテレータを書くより慣用的な方法は、チャネルにまたがっています。同等のプログラムを考えてみましょう:

func Iterator(iterCh chan<- int) {
    for i := 0; i < 10; i++ {
       iterCh <- i
    }
    close(iterCh)
}

func main() {
    iter := make(chan int)
    go Iterator(iter)
    for v := range iter {
       fmt.Println(v)
    }
}

この場合、ブール値を返す代わりに、値の送信が完了したら、チャネルを閉じます。このメソッドの欠点は、複数の値を返したい場合、チャネル経由で送信する何らかの構造体を作成する必要があることです。

最後に、イテレータを実行するたびにチャネルのボイラープレートを非表示にするために少しラップしたい場合は、次のようにします。

func Iter() <-chan int {
   iterChan := make(chan int)
   go iter(iterChan)
   return iterChan
}
func iter(iterCh chan<- int) {
    for i := 0; i < 10; i++ {
       iterCh <- i
    }
    close(iterCh)
}

func main() {
    for v := range Iter() {
       fmt.Println(v)
    }
}

これは初期実装のコードですが、イテレータを使用するたびにチャネルを手動で宣言する必要がなくなります。

于 2013-07-25T19:49:14.587 に答える