golang: read file generator
Question: I'm learning _go_ language and try to rewrite some of my Python code using
golang. I wrote a generator function that reads a text file line by line and
send (using _yield_ keyword) only "valid" lines (blank lines are ignored,
uncompleted lines are recomposed).

Sample file (myfile.txt):

    
    
    #123= FOOBAR(1.,'text');
    
    #126= BARBAZ('poeazpfodsp',
    234,56);
    

parse.py:

    
    
    #!/usr/bin/python
    def validlines(filename):
        with open(filename) as fdin:
            buff = ''
            for line in fdin.readlines():
                line = line.strip()
                if line == '':
                    continue
                buff += line
                if line[-1] != ';':
                    continue
                yield buff
                buff = ''
            fdin.close()
    
    for line in validlines('myfile.txt'):
        print(line) 
    

displays:

    
    
    #123= FOOBAR(1.,'text');
    #126= BARBAZ('poeazpfodsp',234,56);    
    

Now, I try to do it the same way using a closure in golang:

parse.go:

    
    
    package main
    
    import (
        "bufio"
        "fmt"
        "os"
        "strings"
    )
    
    func validLines(filename string) (func() (string, bool)) {
    
        file, _ := os.Open(filename)
        scanner := bufio.NewScanner(file)
    
        return func() (string, bool) {
            buff := ""
            for scanner.Scan() {
                line := scanner.Text()
                line = strings.TrimSpace(line)
    
                if line == "" {
                    continue
                }
                buff += line
                if line[len(line)-1] != ';' {
                    continue
                }
                return buff, true
            }
    
            file.Close()
            return "", false
        }
    }
    
    func main() {
        vline := validLines("myfile.txt")
        for line, ok := vline(); ok; {
            fmt.Println(line)
        }
    }
    

displays:

    
    
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    #123= FOOBAR(1.,'text');
    ...
    

What's the right way to do it in golang?


Answer: In Go you can use channels instead of yield, it's very convenient.

package main

    
    
    import (
        "bufio"
        "fmt"
        "os"
        "strings"
    )
    
    func ValidLines(filename string) (c chan string) {
        c = make(chan string)
        buff := ""
        go func() {
            file, err := os.Open(filename)
            if err != nil {
                close(c)
                return
            }
    
            reader := bufio.NewReader(file)
            for {
                line, err := reader.ReadString('\n')
                if err != nil {
                    close(c)
                    return
                }
                line = strings.TrimSpace(line)
                if line == "" {
                    continue
                }
                buff += line
                if line[len(line)-1] != ';' {
                    continue
                }
                c <- buff
                buff = ""
            }
        }()
        return c
    }
    
    func main() {
        for line := range ValidLines("myfile.txt") {
            fmt.Println(line)
        }
    }
    

