aboutsummaryrefslogtreecommitdiff
path: root/src/bufio/scan.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2015-09-24 13:10:00 -0700
committerRob Pike <r@golang.org>2015-09-25 21:46:13 +0000
commitec12754700c5635c916361c6cd95718f57a8f1c9 (patch)
tree8eda6631b35c06adbae8effa87d7b87e5398738e /src/bufio/scan.go
parentdc6df1b07093ffa0568a581251e8ddd38f707ed6 (diff)
downloadgo-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.go19
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
}