Skip to content

bytes, strings: Lines iterator without reiteration #78549

Description

@mwriter

Go version

1.26.1

Output of go env in your module/workspace:

any

What did you do?

import (
	"fmt"
	"bytes"
	"strings"
)

func main() {
	s := "go"
	
	seq := strings.Lines(s)
	for s := range seq {
		fmt.Println(s)	// go
	}
	for s := range seq { // no iter
		fmt.Println(s)
	}
	
	bseq := bytes.Lines([]byte(s))
	for s := range bseq {
		fmt.Println(s)	// [103 111]
	}
	for s := range bseq { // no iter
		fmt.Println(s)
	}
}

What did you see happen?

The inability to reuse the iterator.

What did you expect to see?

The problem is in the logic of processing the input data.
The easiest way to fix the problem is like

func Lines(s string) iter.Seq[string] {
	return func(yield func(string) bool) {
		var (
			line string
			i int
		)
		cs := s
		for len(cs) > 0 {
			if i = IndexByte(cs, '\n'); i >= 0 {
				line, cs = cs[:i+1], cs[i+1:]
			} else {
				line, cs = cs, ""
			}
			if !yield(line) {
				return
			}
		}
	}
}
func Lines(s []byte) iter.Seq[[]byte] {
	return func(yield func([]byte) bool) {
		var (
			line []byte
			i int
		)
		cs := s
		for len(cs) > 0 {
			if i = IndexByte(cs, '\n'); i >= 0 {
				line, cs = cs[:i+1], cs[i+1:]
			} else {
				line, cs = cs, nil
			}
			if !yield(line[:len(line):len(line)]) {
				return
			}
		}
	}
}

But maybe this code can be optimized better.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions