[Here](http://qiita.com/hiroykam/items/2fea445fd2d489354c34#%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AC%E3%83%BC%E3 When I was investigating generators in PHP and Python3 with% 82% BF), I investigated how it can be realized in Golang and Ruby.
I read numbers.txt
and prepared a simple generator that produces the following output results.
numbers.txt
zero
one
two
three
four
five
Output result
0:zero
1:one
2:two
3:three
4:four
5:five
Verified with PHP 5.6. I didn't select PHP7 because I didn't use yield from
this time.
<?php
function my_generator($name)
{
$file = fopen($name, "r");
if ($file) {
while ($line = fgets($file)) {
yield $line;
}
}
fclose($file);
}
$g = my_generator("numbers.txt");
foreach ($g as $k => $v) {
print($k. ":". $v);
}
It can be achieved in the same way as PHP. I used 3.5 version of Python.
def my_generator(name):
with open(name) as lines:
for line in lines:
yield line
g = my_generator("numbers.txt")
for k, v in enumerate(g):
print("%s:%s" % (k, v), end="")
Golang does not have the equivalent of PHP or Python yield
(see Reference here). Therefore, a similar thing was achieved by using a goroutine channel or closure.
Assuming that the number of lines in numbers.txt
is huge, there are performance concerns.
package main
import (
"bufio"
"fmt"
"os"
)
func yield(fp *os.File) chan string {
ch := make(chan string)
go func() {
defer close(ch)
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
ch <- scanner.Text()
}
if err := scanner.Err(); err != nil {
panic(err)
}
} ()
return ch
}
func main() {
fp, err := os.Open("numbers.txt")
if err != nil {
panic(err)
}
defer fp.Close()
i := 0
for s := range(yield(fp)) {
fmt.Printf("%d:%s\n", i, s)
i++
}
}
There may be a way to synchronize with sync.Mutex
.
package main
import (
"bufio"
"fmt"
"os"
)
func yield(fp *os.File) func() (bool, string) {
scanner := bufio.NewScanner(fp)
return func() (bool, string) {
t := scanner.Scan()
if err := scanner.Err(); err != nil {
panic(err)
}
return t, scanner.Text()
}
}
func main() {
fp, err := os.Open("numbers.txt")
if err != nil {
panic(err)
}
defer fp.Close()
y := yield(fp)
for i := 0;;i++ {
t, s := y()
if !t { break }
fmt.Printf("%d:%s\n", i, s)
}
}
Ruby also has yield
, but it is a function definition that receives blocks instead of a generator like PHP / Python. There is ʻEnumerator` as a function equivalent to the PHP / Python generator, and it is described as follows.
def my_generator(name)
return to_enum(__method__, name) unless block_given?
IO.foreach(name) do |line|
yield(line.chomp)
end
end
g = my_generator('numbers.txt')
g.with_index { |l, i| p '%d:%s' % [i, l] }
Here, if there is a block, it can be processed as a block, and if there is no block, it can be treated as a method that returns Enumerator.
Recommended Posts