diff options
| author | Rob Pike <r@golang.org> | 2015-09-24 13:10:00 -0700 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2015-09-25 21:46:13 +0000 |
| commit | ec12754700c5635c916361c6cd95718f57a8f1c9 (patch) | |
| tree | 8eda6631b35c06adbae8effa87d7b87e5398738e /src/bufio/scan.go | |
| parent | dc6df1b07093ffa0568a581251e8ddd38f707ed6 (diff) | |
| download | go-ec12754700c5635c916361c6cd95718f57a8f1c9.tar.xz | |
bufio: fix scanning with a final empty token.
The Scan function's interface to the split function was not sufficient
to handle an empty final token in a pure function; state was required.
This was ugly.
We introduce a special error value that a split function can return
that signals that this token is OK, but is the last one and scanning
should stop immediately _after_ this token.
The same effect could be achieved using the same trick (a special
error value) and checking for that error after Scan finishes, but it's
a little clumsy. Providing a published sentinel value in bufio is
cleaner and means everyone can use the same trick. The result
is an error-free scan.
Rewrite the test (that was only barely working) to use the value
and be more robust.
Also write a new example showing how to do it.
Fixes #11836
Change-Id: Iaae77d0f95b4a2efa0175ced94d93c66353079e8
Reviewed-on: https://go-review.googlesource.com/14924
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/bufio/scan.go')
| -rw-r--r-- | src/bufio/scan.go | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/bufio/scan.go b/src/bufio/scan.go index 0ec584b027..27a0f00459 100644 --- a/src/bufio/scan.go +++ b/src/bufio/scan.go @@ -38,6 +38,7 @@ type Scanner struct { err error // Sticky error. empties int // Count of successive empty tokens. scanCalled bool // Scan has been called; buffer is in use. + done bool // Scan has finished. } // SplitFunc is the signature of the split function used to tokenize the @@ -106,6 +107,16 @@ func (s *Scanner) Text() string { return string(s.token) } +// ErrFinalToken is a special sentinel error value. It is intended to be +// returned by a Split function to indicate that the token being delivered +// with the error is the last token and scanning should stop after this one. +// After ErrFinalToken is received by Scan, scanning stops with no error. +// The value is useful to stop processing early or when it is necessary to +// deliver a final empty token. One could achieve the same behavior +// with a custom error value but providing one here is tidier. +// See the emptyFinalToken example for a use of this value. +var ErrFinalToken = errors.New("final token") + // Scan advances the Scanner to the next token, which will then be // available through the Bytes or Text method. It returns false when the // scan stops, either by reaching the end of the input or an error. @@ -115,6 +126,9 @@ func (s *Scanner) Text() string { // Scan panics if the split function returns 100 empty tokens without // advancing the input. This is a common error mode for scanners. func (s *Scanner) Scan() bool { + if s.done { + return false + } s.scanCalled = true // Loop until we have a token. for { @@ -124,6 +138,11 @@ func (s *Scanner) Scan() bool { if s.end > s.start || s.err != nil { advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil) if err != nil { + if err == ErrFinalToken { + s.token = token + s.done = true + return true + } s.setErr(err) return false } |
