Go の例(4) (ゴルーチン)
クロージャーを使っている部分をゴルーチンで置き換えたものを考えます。
イテレーターをゴルーチンで実装した IteratorChannelImpl_int 構造体と IteratorChannelIOImpl_Numbers 構造体を作成します。
type IteratorChannelImpl_int struct { ch chan int current_digit int } func newIteratorChannelImpl_int(ch chan int) *IteratorChannelImpl_int { xyz := new(IteratorChannelImpl_int) xyz.ch = ch xyz.current_digit = 0 return xyz } func (xyz *IteratorChannelImpl_int) GetCurrent() int { return xyz.current_digit } func (xyz *IteratorChannelImpl_int) MoveNext() bool { val, ok := <-xyz.ch xyz.current_digit = val return ok } func (xyz *IteratorChannelImpl_int) Take(count int) []int { res := make([]int, count) iter := xyz for i := 0; i < count && iter.MoveNext(); i++ { res[i] = iter.GetCurrent() } return res }
type IteratorChannelIOImpl_Numbers struct { ch_get chan *Numbers ch_set chan *Numbers current_numbers *Numbers } func newIteratorChannelIOImpl_Numbers(ch_get chan *Numbers, ch_set chan *Numbers) *IteratorChannelIOImpl_Numbers { xyz := new(IteratorChannelIOImpl_Numbers) xyz.ch_get = ch_get xyz.ch_set = ch_set xyz.current_numbers = <-xyz.ch_get return xyz } func (xyz *IteratorChannelIOImpl_Numbers) GetCurrent() *Numbers { return xyz.current_numbers } func (xyz *IteratorChannelIOImpl_Numbers) SetCurrent(value *Numbers) { xyz.ch_set <- value } func (xyz *IteratorChannelIOImpl_Numbers) MoveNext() bool { val, ok := <-xyz.ch_get xyz.current_numbers = val return ok } func (xyz *IteratorChannelIOImpl_Numbers) Take(count int) []*Numbers { res := make([]*Numbers, count) iter := xyz for i := 0; i < count && iter.MoveNext(); i++ { res[i] = iter.GetCurrent() } return res }
NumbersGenerator 構造体とそのメソッドは以下のように IteratorChannelImpl_int 構造体で実装します。
type NumbersGenerator struct { generator *IteratorChannelImpl_int } func newNumbersGenerator() *NumbersGenerator { xyz := new(NumbersGenerator) xyz.generator = xyz.GenerateDecimal() return xyz } func (xyz *NumbersGenerator) GetNextDecimalDigit() int { xyz.generator.MoveNext() return xyz.generator.GetCurrent() } func (xyz *NumbersGenerator) GenerateDecimal() *IteratorChannelImpl_int { ch := make(chan int) serv := func(ch chan int) { number := newLongDecimal([]int{}) square_difference := newLongDecimal([]int{3}) nums := newNumbers(number, square_difference, 0) for { ch <- nums.GetNextDecimalDigit() } } go serv(ch) return newIteratorChannelImpl_int(ch) }
NumbersServer 構造体とそのメソッドは以下のように IteratorChannelIOImpl_Numbers 構造体で実装します。
type NumbersServer struct { current_numbers *Numbers generator_server *IteratorChannelIOImpl_Numbers } func newNumbersServer() *NumbersServer { xyz := new(NumbersServer) xyz.current_numbers = newNumbers(newLongDecimal([]int{}), newLongDecimal([]int{}), 0) xyz.generator_server = xyz.GenerateDecimalServer() return xyz } func (xyz *NumbersServer) GetNumbers() *Numbers { return xyz.generator_server.GetCurrent() } func (xyz *NumbersServer) SetNumbers(numbers *Numbers) { xyz.generator_server.SetCurrent(numbers) } func (xyz *NumbersServer) GenerateDecimalServer() *IteratorChannelIOImpl_Numbers { ch_get := make(chan *Numbers) ch_set := make(chan *Numbers) serv := func(ch_get chan *Numbers, ch_set chan *Numbers) { number := newLongDecimal([]int{}) square_difference := newLongDecimal([]int{3}) nums := newNumbers(number, square_difference, 0) for { ch_get <- nums nums = <-ch_set } } go serv(ch_get, ch_set) return newIteratorChannelIOImpl_Numbers(ch_get, ch_set) }
Iterate 関数を使っている部分について、今までの例では実行順序が固定だったので問題なかったのですが、ゴルーチンを使ったこの例では実行順序が不定となるようです。間違っていたところを修正することにします。この修正は今までの例でもやった方が良いです。
Numbers 構造体をコピーするメソッドを作成します。
func (xyz *Numbers) Copy() *Numbers { return newNumbers(xyz.number, xyz.square_difference, xyz.scale) }
NextNumbers 関数を構造体をコピーするように修正します。
func NextNumbers(numbers *Numbers) *Numbers { new_numbers := numbers.Copy() new_numbers.GetNextDecimalDigit() return new_numbers }