From 68050ac76b94b58d962cf8265a8d4eb31ff35658 Mon Sep 17 00:00:00 2001
From: Rob Pike
@@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
// Compile parses a regular expression and returns, if successful, a Regexp
// object that can be used to match against text.
-func Compile(str string) (regexp *Regexp, error os.Error) {
+func Compile(str string) (regexp *Regexp, err error) {
// Error codes returned by failures to parse an expression.
var (
- ErrInternal = os.NewError("regexp: internal error")
- ErrUnmatchedLpar = os.NewError("regexp: unmatched '('")
- ErrUnmatchedRpar = os.NewError("regexp: unmatched ')'")
+ ErrInternal = errors.New("regexp: internal error")
+ ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
+ ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
...
)
@@ -717,12 +717,12 @@ The signature of *File.Write
in package os
is:
-func (file *File) Write(b []byte) (n int, err Error) +func (file *File) Write(b []byte) (n int, err error)
and as the documentation says, it returns the number of bytes
-written and a non-nil Error
when n
+written and a non-nil error
when n
!=
len(b)
.
This is a common style; see the section on error handling for more examples.
io.ReadFull
that uses them well:
-func ReadFull(r Reader, buf []byte) (n int, err os.Error) { +func ReadFull(r Reader, buf []byte) (n int, err error) { for len(buf) > 0 && err == nil { var nr int nr, err = r.Read(buf) @@ -812,7 +812,7 @@ canonical examples are unlocking a mutex or closing a file.// Contents returns the file's contents as a string. -func Contents(filename string) (string, os.Error) { +func Contents(filename string) (string, error) { f, err := os.Open(filename) if err != nil { return "", err @@ -1195,7 +1195,7 @@ limit of how much data to read. Here is the signature of theos
:-func (file *File) Read(buf []byte) (n int, err os.Error) +func (file *File) Read(buf []byte) (n int, err error)The method returns the number of bytes read and an error value, if @@ -1211,7 +1211,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer.
var n int - var err os.Error + var err error for i := 0; i < 32; i++ { nbytes, e := f.Read(buf[i:i+1]) // Read one byte. if nbytes == 0 || e != nil { @@ -1509,7 +1509,7 @@ for its final argument to specify that an arbitrary number of parameters (of arb can appear after the format.-func Printf(format string, v ...interface{}) (n int, errno os.Error) { +func Printf(format string, v ...interface{}) (n int, err error) {Within the function
Printf
,v
acts like a variable of type @@ -1760,7 +1760,7 @@ In fact, we can do even better. If we modify our function so it looks like a standardWrite
method, like this,-func (p *ByteSlice) Write(data []byte) (n int, err os.Error) { +func (p *ByteSlice) Write(data []byte) (n int, err error) { slice := *p // Again as above. *p = slice @@ -2119,11 +2119,11 @@ here are their definitions.type Reader interface { - Read(p []byte) (n int, err os.Error) + Read(p []byte) (n int, err error) } type Writer interface { - Write(p []byte) (n int, err os.Error) + Write(p []byte) (n int, err error) }@@ -2185,7 +2185,7 @@ satisfy the
io
interfaces, we would also need to provide forwarding methods, like this:-func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) { +func (rw *ReadWriter) Read(p []byte) (n int, err error) { return rw.reader.Read(p) }@@ -2637,12 +2637,12 @@ the garbage collector for bookkeeping. Library routines must often return some sort of error indication to the caller. As mentioned earlier, Go's multivalue return makes it easy to return a detailed error description alongside the normal -return value. By convention, errors have typeos.Error
, -a simple interface. +return value. By convention, errors have typeerror
, +a simple built-in interface.-type Error interface { - String() string +type error interface { + Error() string }@@ -2657,15 +2657,15 @@ For example,
os.Open
returns anos.PathError
. type PathError struct { Op string // "open", "unlink", etc. Path string // The associated file. - Error Error // Returned by the system call. + Err error // Returned by the system call. } -func (e *PathError) String() string { - return e.Op + " " + e.Path + ": " + e.Error.String() +func (e *PathError) Error() string { + return e.Op + " " + e.Path + ": " + e.Err.Error() }-
PathError
'sString
generates +PathError
'sError
generates a string like this:@@ -2690,7 +2690,7 @@ is "image: unknown format". Callers that care about the precise error details can use a type switch or a type assertion to look for specific errors and extract details. ForPathErrors
-this might include examining the internalError
+this might include examining the internalErr
field for recoverable failures. @@ -2700,7 +2700,7 @@ for try := 0; try < 2; try++ { if err == nil { return } - if e, ok := err.(*os.PathError); ok && e.Error == os.ENOSPC { + if e, ok := err.(*os.PathError); ok && e.Err == os.ENOSPC { deleteTempFiles() // Recover some space. continue } @@ -2712,9 +2712,9 @@ for try := 0; try < 2; try++ {The usual way to report an error to a caller is to return an -
@@ -2830,14 +2830,14 @@ cleanly by callingos.Error
as an extra return value. The canonical +error
as an extra return value. The canonicalRead
method is a well-known instance; it returns a byte -count and anos.Error
. But what if the error is +count and anerror
. But what if the error is unrecoverable? Sometimes the program simply cannot continue.panic
. We can use that idea to simplify error handling in complex software. Let's look at an idealized excerpt from theregexp
package, which reports parsing errors by callingpanic
with a local -Error
type. Here's the definition ofError
, +error type. Here's the definition ofError
, anerror
method, and theCompile
function.-// Error is the type of a parse error; it satisfies os.Error. +// Error is the type of a parse error; it satisfies the error interface. type Error string -func (e Error) String() string { +func (e Error) Error() string { return string(e) } @@ -2848,7 +2848,7 @@ func (regexp *Regexp) error(err string) { } // Compile returns a parsed representation of the regular expression. -func Compile(str string) (regexp *Regexp, err os.Error) { +func Compile(str string) (regexp *Regexp, err error) { regexp = new(Regexp) // doParse will panic if there is a parse error. defer func() { @@ -2866,7 +2866,7 @@ IfdoParse
panics, the recovery block will set the return value tonil
—deferred functions can modify named return values. It then will then check, in the assignment toerr
, that the problem was a parse error by asserting -that it has typeError
. +that it has the local typeError
. If it does not, the type assertion will fail, causing a run-time error that continues the stack unwinding as though nothing had interrupted it. This check means that if something unexpected happens, such @@ -2884,7 +2884,7 @@ the parse stack by hand.Useful though this pattern is, it should be used only within a package.
diff --git a/doc/effective_go.tmpl b/doc/effective_go.tmpl index da827368b1..aa011f2a01 100644 --- a/doc/effective_go.tmpl +++ b/doc/effective_go.tmpl @@ -221,7 +221,7 @@ starts with the name being declared.Parse
turns its internalpanic
calls into -os.Error
values; it does not exposepanics
+error
values; it does not exposepanics
to its client. That is a good rule to follow.// Compile parses a regular expression and returns, if successful, a Regexp // object that can be used to match against text. -func Compile(str string) (regexp *Regexp, error os.Error) { +func Compile(str string) (regexp *Regexp, err error) {@@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
// Error codes returned by failures to parse an expression. var ( - ErrInternal = os.NewError("regexp: internal error") - ErrUnmatchedLpar = os.NewError("regexp: unmatched '('") - ErrUnmatchedRpar = os.NewError("regexp: unmatched ')'") + ErrInternal = errors.New("regexp: internal error") + ErrUnmatchedLpar = errors.New("regexp: unmatched '('") + ErrUnmatchedRpar = errors.New("regexp: unmatched ')'") ... )@@ -717,12 +717,12 @@ The signature of*File.Write
in packageos
is:-func (file *File) Write(b []byte) (n int, err Error) +func (file *File) Write(b []byte) (n int, err error)and as the documentation says, it returns the number of bytes -written and a non-nil
@@ -788,7 +788,7 @@ ofError
whenn
+written and a non-nilerror
whenn
!=
len(b)
. This is a common style; see the section on error handling for more examples.io.ReadFull
that uses them well:-func ReadFull(r Reader, buf []byte) (n int, err os.Error) { +func ReadFull(r Reader, buf []byte) (n int, err error) { for len(buf) > 0 && err == nil { var nr int nr, err = r.Read(buf) @@ -812,7 +812,7 @@ canonical examples are unlocking a mutex or closing a file.// Contents returns the file's contents as a string. -func Contents(filename string) (string, os.Error) { +func Contents(filename string) (string, error) { f, err := os.Open(filename) if err != nil { return "", err @@ -1195,7 +1195,7 @@ limit of how much data to read. Here is the signature of theos
:-func (file *File) Read(buf []byte) (n int, err os.Error) +func (file *File) Read(buf []byte) (n int, err error)The method returns the number of bytes read and an error value, if @@ -1211,7 +1211,7 @@ the moment, this snippet would also read the first 32 bytes of the buffer.
var n int - var err os.Error + var err error for i := 0; i < 32; i++ { nbytes, e := f.Read(buf[i:i+1]) // Read one byte. if nbytes == 0 || e != nil { @@ -1509,7 +1509,7 @@ for its final argument to specify that an arbitrary number of parameters (of arb can appear after the format.-func Printf(format string, v ...interface{}) (n int, errno os.Error) { +func Printf(format string, v ...interface{}) (n int, err error) {Within the function
Printf
,v
acts like a variable of type @@ -1724,7 +1724,7 @@ In fact, we can do even better. If we modify our function so it looks like a standardWrite
method, like this,-func (p *ByteSlice) Write(data []byte) (n int, err os.Error) { +func (p *ByteSlice) Write(data []byte) (n int, err error) { slice := *p // Again as above. *p = slice @@ -2057,11 +2057,11 @@ here are their definitions.type Reader interface { - Read(p []byte) (n int, err os.Error) + Read(p []byte) (n int, err error) } type Writer interface { - Write(p []byte) (n int, err os.Error) + Write(p []byte) (n int, err error) }@@ -2123,7 +2123,7 @@ satisfy the
io
interfaces, we would also need to provide forwarding methods, like this:-func (rw *ReadWriter) Read(p []byte) (n int, err os.Error) { +func (rw *ReadWriter) Read(p []byte) (n int, err error) { return rw.reader.Read(p) }@@ -2575,12 +2575,12 @@ the garbage collector for bookkeeping. Library routines must often return some sort of error indication to the caller. As mentioned earlier, Go's multivalue return makes it easy to return a detailed error description alongside the normal -return value. By convention, errors have typeos.Error
, -a simple interface. +return value. By convention, errors have typeerror
, +a simple built-in interface.-type Error interface { - String() string +type error interface { + Error() string }@@ -2595,15 +2595,15 @@ For example,
os.Open
returns anos.PathError
. type PathError struct { Op string // "open", "unlink", etc. Path string // The associated file. - Error Error // Returned by the system call. + Err error // Returned by the system call. } -func (e *PathError) String() string { - return e.Op + " " + e.Path + ": " + e.Error.String() +func (e *PathError) Error() string { + return e.Op + " " + e.Path + ": " + e.Err.Error() }-
PathError
'sString
generates +PathError
'sError
generates a string like this:@@ -2628,7 +2628,7 @@ is "image: unknown format". Callers that care about the precise error details can use a type switch or a type assertion to look for specific errors and extract details. ForPathErrors
-this might include examining the internalError
+this might include examining the internalErr
field for recoverable failures. @@ -2638,7 +2638,7 @@ for try := 0; try < 2; try++ { if err == nil { return } - if e, ok := err.(*os.PathError); ok && e.Error == os.ENOSPC { + if e, ok := err.(*os.PathError); ok && e.Err == os.ENOSPC { deleteTempFiles() // Recover some space. continue } @@ -2650,9 +2650,9 @@ for try := 0; try < 2; try++ {The usual way to report an error to a caller is to return an -
@@ -2768,14 +2768,14 @@ cleanly by callingos.Error
as an extra return value. The canonical +error
as an extra return value. The canonicalRead
method is a well-known instance; it returns a byte -count and anos.Error
. But what if the error is +count and anerror
. But what if the error is unrecoverable? Sometimes the program simply cannot continue.panic
. We can use that idea to simplify error handling in complex software. Let's look at an idealized excerpt from theregexp
package, which reports parsing errors by callingpanic
with a local -Error
type. Here's the definition ofError
, +error type. Here's the definition ofError
, anerror
method, and theCompile
function.-// Error is the type of a parse error; it satisfies os.Error. +// Error is the type of a parse error; it satisfies the error interface. type Error string -func (e Error) String() string { +func (e Error) Error() string { return string(e) } @@ -2786,7 +2786,7 @@ func (regexp *Regexp) error(err string) { } // Compile returns a parsed representation of the regular expression. -func Compile(str string) (regexp *Regexp, err os.Error) { +func Compile(str string) (regexp *Regexp, err error) { regexp = new(Regexp) // doParse will panic if there is a parse error. defer func() { @@ -2804,7 +2804,7 @@ IfdoParse
panics, the recovery block will set the return value tonil
—deferred functions can modify named return values. It then will then check, in the assignment toerr
, that the problem was a parse error by asserting -that it has typeError
. +that it has the local typeError
. If it does not, the type assertion will fail, causing a run-time error that continues the stack unwinding as though nothing had interrupted it. This check means that if something unexpected happens, such @@ -2822,7 +2822,7 @@ the parse stack by hand.Useful though this pattern is, it should be used only within a package.
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html index 40c793057f..aa8db870d3 100644 --- a/doc/go_tutorial.html +++ b/doc/go_tutorial.html @@ -578,11 +578,13 @@ to see that). Finally,Parse
turns its internalpanic
calls into -os.Error
values; it does not exposepanics
+error
values; it does not exposepanics
to its client. That is a good rule to follow.OpenFile
returns two values: a pointer to t and the error. Ifsyscall.Open
fails, the file descriptorr
will be negative andnewFile
will returnnil
.-About those errors: The
os
library includes a general notion of an error. +About those errors: The Go language includes a general notion of an error: +a pre-defined typeerror
with properties (described below) +that make it a good basis for representing and handling errors. It's a good idea to use its facility in your own interfaces, as we do here, for consistent error handling throughout Go code. InOpen
we use a conversion to translate Unix's integererrno
value into the integer type -os.Errno
, which implementsos.Error
. +os.Errno
, which is an implementation oferror
Why
OpenFile
and notOpen
? To mimic Go'sos
package, which our exercise is emulating. Theos
package takes the opportunity @@ -668,7 +670,7 @@ array, not just forstructs
. We'll see an example with arrays lat TheString
method is so called because of a printing convention we'll describe later.-The methods use the public variable
os.EINVAL
to return the (os.Error
+The methods use the public variableos.EINVAL
to return the (error
version of the) Unix error codeEINVAL
. Theos
library defines a standard set of such error values.@@ -733,13 +735,13 @@ func cat(f *file.File) { for { switch nr, er := f.Read(buf[:]); true { case nr < 0: - fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String()) + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f, er) os.Exit(1) case nr == 0: // EOF return case nr > 0: if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { - fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String()) + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f, ew) os.Exit(1) } } @@ -850,14 +852,14 @@ and use it from within a mostly unchanged
cat
function: for { switch nr, er := r.Read(buf[:]); { case nr < 0: - fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String()) + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r, er) os.Exit(1) case nr == 0: // EOF return case nr > 0: nw, ew := file.Stdout.Write(buf[0:nr]) if nw != nr { - fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String()) + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r, ew) os.Exit(1) } } @@ -990,7 +992,7 @@ implementsPrintf
,Fprintf
, and so on. Within thefmt
package,Printf
is declared with this signature:
-Printf(format string, v ...interface{}) (n int, errno os.Error) +Printf(format string, v ...interface{}) (n int, errno error)The token
...
introduces a variable-length argument list that in C would @@ -1127,6 +1129,21 @@ If the value does not satisfy the interface,ok
will be false. In this snippet the nameStringer
follows the convention that we add ''[e]r'' to interfaces describing simple method sets like this.+A related interface is that defined by the
error
builtin type, which is just ++
+type error interface { + Error() string +} +++Other than the method name (
Error
vs.String
), this looks like +aStringer
; the different name guarantees that types that implementStringer
+don't accidentally satisfy theerror
interface. +Naturally,Printf
and its relatives recognize theerror
interface, +just as they doStringer
, +so it's trivial to print an error as a string. +One last wrinkle. To complete the suite, besides
Printf
etc. andSprintf
etc., there are alsoFprintf
etc. Unlike in C,Fprintf
's first argument is not a file. Instead, it is a variable of typeio.Writer
, which is an @@ -1134,7 +1151,7 @@ interface type defined in theio
library:
type Writer interface { - Write(p []byte) (n int, err os.Error) + Write(p []byte) (n int, err error) }diff --git a/doc/go_tutorial.tmpl b/doc/go_tutorial.tmpl index 4377dabde0..21496ddd98 100644 --- a/doc/go_tutorial.tmpl +++ b/doc/go_tutorial.tmpl @@ -490,11 +490,13 @@ to see that). Finally,
OpenFile
returns two values: a pointer to t and the error. Ifsyscall.Open
fails, the file descriptorr
will be negative andnewFile
will returnnil
.-About those errors: The
os
library includes a general notion of an error. +About those errors: The Go language includes a general notion of an error: +a pre-defined typeerror
with properties (described below) +that make it a good basis for representing and handling errors. It's a good idea to use its facility in your own interfaces, as we do here, for consistent error handling throughout Go code. InOpen
we use a conversion to translate Unix's integererrno
value into the integer type -os.Errno
, which implementsos.Error
. +os.Errno
, which is an implementation oferror
Why
OpenFile
and notOpen
? To mimic Go'sos
package, which our exercise is emulating. Theos
package takes the opportunity @@ -527,7 +529,7 @@ array, not just forstructs
. We'll see an example with arrays lat TheString
method is so called because of a printing convention we'll describe later.-The methods use the public variable
os.EINVAL
to return the (os.Error
+The methods use the public variableos.EINVAL
to return the (error
version of the) Unix error codeEINVAL
. Theos
library defines a standard set of such error values.@@ -692,7 +694,7 @@ implements
Printf
,Fprintf
, and so on. Within thefmt
package,Printf
is declared with this signature:
-Printf(format string, v ...interface{}) (n int, errno os.Error) +Printf(format string, v ...interface{}) (n int, errno error)The token
...
introduces a variable-length argument list that in C would @@ -801,6 +803,21 @@ If the value does not satisfy the interface,ok
will be false. In this snippet the nameStringer
follows the convention that we add ''[e]r'' to interfaces describing simple method sets like this.+A related interface is that defined by the
error
builtin type, which is just ++
+type error interface { + Error() string +} +++Other than the method name (
Error
vs.String
), this looks like +aStringer
; the different name guarantees that types that implementStringer
+don't accidentally satisfy theerror
interface. +Naturally,Printf
and its relatives recognize theerror
interface, +just as they doStringer
, +so it's trivial to print an error as a string. +One last wrinkle. To complete the suite, besides
Printf
etc. andSprintf
etc., there are alsoFprintf
etc. Unlike in C,Fprintf
's first argument is not a file. Instead, it is a variable of typeio.Writer
, which is an @@ -808,7 +825,7 @@ interface type defined in theio
library:
type Writer interface { - Write(p []byte) (n int, err os.Error) + Write(p []byte) (n int, err error) }diff --git a/doc/progs/cat.go b/doc/progs/cat.go index 9f0b8d4a3e..79ad015039 100644 --- a/doc/progs/cat.go +++ b/doc/progs/cat.go @@ -17,13 +17,13 @@ func cat(f *file.File) { for { switch nr, er := f.Read(buf[:]); true { case nr < 0: - fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String()) + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f, er) os.Exit(1) case nr == 0: // EOF return case nr > 0: if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr { - fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f.String(), ew.String()) + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", f, ew) os.Exit(1) } } diff --git a/doc/progs/cat_rot13.go b/doc/progs/cat_rot13.go index 0eefe7cfc7..5df5972020 100644 --- a/doc/progs/cat_rot13.go +++ b/doc/progs/cat_rot13.go @@ -59,14 +59,14 @@ func cat(r reader) { for { switch nr, er := r.Read(buf[:]); { case nr < 0: - fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String()) + fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r, er) os.Exit(1) case nr == 0: // EOF return case nr > 0: nw, ew := file.Stdout.Write(buf[0:nr]) if nw != nr { - fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r.String(), ew.String()) + fmt.Fprintf(os.Stderr, "cat: error writing from %s: %s\n", r, ew) os.Exit(1) } }