mirror of
https://github.com/golang/go
synced 2024-11-22 01:24:42 -07:00
tutorial,effective_go: prepare for error change
R=adg, rsc CC=golang-dev https://golang.org/cl/5316068
This commit is contained in:
parent
451a1fa46d
commit
68050ac76b
@ -221,7 +221,7 @@ starts with the name being declared.
|
|||||||
<pre>
|
<pre>
|
||||||
// Compile parses a regular expression and returns, if successful, a Regexp
|
// Compile parses a regular expression and returns, if successful, a Regexp
|
||||||
// object that can be used to match against text.
|
// 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) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
|
|||||||
<pre>
|
<pre>
|
||||||
// Error codes returned by failures to parse an expression.
|
// Error codes returned by failures to parse an expression.
|
||||||
var (
|
var (
|
||||||
ErrInternal = os.NewError("regexp: internal error")
|
ErrInternal = errors.New("regexp: internal error")
|
||||||
ErrUnmatchedLpar = os.NewError("regexp: unmatched '('")
|
ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
|
||||||
ErrUnmatchedRpar = os.NewError("regexp: unmatched ')'")
|
ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
|
||||||
...
|
...
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
@ -717,12 +717,12 @@ The signature of <code>*File.Write</code> in package <code>os</code> is:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
func (file *File) Write(b []byte) (n int, err Error)
|
func (file *File) Write(b []byte) (n int, err error)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
and as the documentation says, it returns the number of bytes
|
and as the documentation says, it returns the number of bytes
|
||||||
written and a non-nil <code>Error</code> when <code>n</code>
|
written and a non-nil <code>error</code> when <code>n</code>
|
||||||
<code>!=</code> <code>len(b)</code>.
|
<code>!=</code> <code>len(b)</code>.
|
||||||
This is a common style; see the section on error handling for more examples.
|
This is a common style; see the section on error handling for more examples.
|
||||||
</p>
|
</p>
|
||||||
@ -788,7 +788,7 @@ of <code>io.ReadFull</code> that uses them well:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
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 {
|
for len(buf) > 0 && err == nil {
|
||||||
var nr int
|
var nr int
|
||||||
nr, err = r.Read(buf)
|
nr, err = r.Read(buf)
|
||||||
@ -812,7 +812,7 @@ canonical examples are unlocking a mutex or closing a file.
|
|||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// Contents returns the file's contents as a string.
|
// 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)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -1195,7 +1195,7 @@ limit of how much data to read. Here is the signature of the
|
|||||||
<code>os</code>:
|
<code>os</code>:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func (file *File) Read(buf []byte) (n int, err os.Error)
|
func (file *File) Read(buf []byte) (n int, err error)
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
The method returns the number of bytes read and an error value, if
|
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.
|
|||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
var n int
|
var n int
|
||||||
var err os.Error
|
var err error
|
||||||
for i := 0; i < 32; i++ {
|
for i := 0; i < 32; i++ {
|
||||||
nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
|
nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
|
||||||
if nbytes == 0 || e != nil {
|
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.
|
can appear after the format.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func Printf(format string, v ...interface{}) (n int, errno os.Error) {
|
func Printf(format string, v ...interface{}) (n int, err error) {
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Within the function <code>Printf</code>, <code>v</code> acts like a variable of type
|
Within the function <code>Printf</code>, <code>v</code> 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 standard <code>Write</code> method, like this,
|
like a standard <code>Write</code> method, like this,
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
|
func (p *ByteSlice) Write(data []byte) (n int, err error) {
|
||||||
slice := *p
|
slice := *p
|
||||||
// Again as above.
|
// Again as above.
|
||||||
*p = slice
|
*p = slice
|
||||||
@ -2119,11 +2119,11 @@ here are their definitions.
|
|||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
Read(p []byte) (n int, err os.Error)
|
Read(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(p []byte) (n int, err os.Error)
|
Write(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -2185,7 +2185,7 @@ satisfy the <code>io</code> interfaces, we would also need
|
|||||||
to provide forwarding methods, like this:
|
to provide forwarding methods, like this:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
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)
|
return rw.reader.Read(p)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -2637,12 +2637,12 @@ the garbage collector for bookkeeping.
|
|||||||
Library routines must often return some sort of error indication to
|
Library routines must often return some sort of error indication to
|
||||||
the caller. As mentioned earlier, Go's multivalue return makes it
|
the caller. As mentioned earlier, Go's multivalue return makes it
|
||||||
easy to return a detailed error description alongside the normal
|
easy to return a detailed error description alongside the normal
|
||||||
return value. By convention, errors have type <code>os.Error</code>,
|
return value. By convention, errors have type <code>error</code>,
|
||||||
a simple interface.
|
a simple built-in interface.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
type Error interface {
|
type error interface {
|
||||||
String() string
|
Error() string
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -2657,15 +2657,15 @@ For example, <code>os.Open</code> returns an <code>os.PathError</code>.
|
|||||||
type PathError struct {
|
type PathError struct {
|
||||||
Op string // "open", "unlink", etc.
|
Op string // "open", "unlink", etc.
|
||||||
Path string // The associated file.
|
Path string // The associated file.
|
||||||
Error Error // Returned by the system call.
|
Err error // Returned by the system call.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PathError) String() string {
|
func (e *PathError) Error() string {
|
||||||
return e.Op + " " + e.Path + ": " + e.Error.String()
|
return e.Op + " " + e.Path + ": " + e.Err.Error()
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
<code>PathError</code>'s <code>String</code> generates
|
<code>PathError</code>'s <code>Error</code> generates
|
||||||
a string like this:
|
a string like this:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
@ -2690,7 +2690,7 @@ is "image: unknown format".
|
|||||||
Callers that care about the precise error details can
|
Callers that care about the precise error details can
|
||||||
use a type switch or a type assertion to look for specific
|
use a type switch or a type assertion to look for specific
|
||||||
errors and extract details. For <code>PathErrors</code>
|
errors and extract details. For <code>PathErrors</code>
|
||||||
this might include examining the internal <code>Error</code>
|
this might include examining the internal <code>Err</code>
|
||||||
field for recoverable failures.
|
field for recoverable failures.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -2700,7 +2700,7 @@ for try := 0; try < 2; try++ {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
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.
|
deleteTempFiles() // Recover some space.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -2712,9 +2712,9 @@ for try := 0; try < 2; try++ {
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The usual way to report an error to a caller is to return an
|
The usual way to report an error to a caller is to return an
|
||||||
<code>os.Error</code> as an extra return value. The canonical
|
<code>error</code> as an extra return value. The canonical
|
||||||
<code>Read</code> method is a well-known instance; it returns a byte
|
<code>Read</code> method is a well-known instance; it returns a byte
|
||||||
count and an <code>os.Error</code>. But what if the error is
|
count and an <code>error</code>. But what if the error is
|
||||||
unrecoverable? Sometimes the program simply cannot continue.
|
unrecoverable? Sometimes the program simply cannot continue.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -2830,14 +2830,14 @@ cleanly by calling <code>panic</code>. We can use that idea to
|
|||||||
simplify error handling in complex software. Let's look at an
|
simplify error handling in complex software. Let's look at an
|
||||||
idealized excerpt from the <code>regexp</code> package, which reports
|
idealized excerpt from the <code>regexp</code> package, which reports
|
||||||
parsing errors by calling <code>panic</code> with a local
|
parsing errors by calling <code>panic</code> with a local
|
||||||
<code>Error</code> type. Here's the definition of <code>Error</code>,
|
error type. Here's the definition of <code>Error</code>,
|
||||||
an <code>error</code> method, and the <code>Compile</code> function.
|
an <code>error</code> method, and the <code>Compile</code> function.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// 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
|
type Error string
|
||||||
func (e Error) String() string {
|
func (e Error) Error() string {
|
||||||
return string(e)
|
return string(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2848,7 +2848,7 @@ func (regexp *Regexp) error(err string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile returns a parsed representation of the regular expression.
|
// 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)
|
regexp = new(Regexp)
|
||||||
// doParse will panic if there is a parse error.
|
// doParse will panic if there is a parse error.
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -2866,7 +2866,7 @@ If <code>doParse</code> panics, the recovery block will set the
|
|||||||
return value to <code>nil</code>—deferred functions can modify
|
return value to <code>nil</code>—deferred functions can modify
|
||||||
named return values. It then will then check, in the assignment
|
named return values. It then will then check, in the assignment
|
||||||
to <code>err</code>, that the problem was a parse error by asserting
|
to <code>err</code>, that the problem was a parse error by asserting
|
||||||
that it has type <code>Error</code>.
|
that it has the local type <code>Error</code>.
|
||||||
If it does not, the type assertion will fail, causing a run-time error
|
If it does not, the type assertion will fail, causing a run-time error
|
||||||
that continues the stack unwinding as though nothing had interrupted
|
that continues the stack unwinding as though nothing had interrupted
|
||||||
it. This check means that if something unexpected happens, such
|
it. This check means that if something unexpected happens, such
|
||||||
@ -2884,7 +2884,7 @@ the parse stack by hand.
|
|||||||
<p>
|
<p>
|
||||||
Useful though this pattern is, it should be used only within a package.
|
Useful though this pattern is, it should be used only within a package.
|
||||||
<code>Parse</code> turns its internal <code>panic</code> calls into
|
<code>Parse</code> turns its internal <code>panic</code> calls into
|
||||||
<code>os.Error</code> values; it does not expose <code>panics</code>
|
<code>error</code> values; it does not expose <code>panics</code>
|
||||||
to its client. That is a good rule to follow.
|
to its client. That is a good rule to follow.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ starts with the name being declared.
|
|||||||
<pre>
|
<pre>
|
||||||
// Compile parses a regular expression and returns, if successful, a Regexp
|
// Compile parses a regular expression and returns, if successful, a Regexp
|
||||||
// object that can be used to match against text.
|
// 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) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
|
|||||||
<pre>
|
<pre>
|
||||||
// Error codes returned by failures to parse an expression.
|
// Error codes returned by failures to parse an expression.
|
||||||
var (
|
var (
|
||||||
ErrInternal = os.NewError("regexp: internal error")
|
ErrInternal = errors.New("regexp: internal error")
|
||||||
ErrUnmatchedLpar = os.NewError("regexp: unmatched '('")
|
ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
|
||||||
ErrUnmatchedRpar = os.NewError("regexp: unmatched ')'")
|
ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
|
||||||
...
|
...
|
||||||
)
|
)
|
||||||
</pre>
|
</pre>
|
||||||
@ -717,12 +717,12 @@ The signature of <code>*File.Write</code> in package <code>os</code> is:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
func (file *File) Write(b []byte) (n int, err Error)
|
func (file *File) Write(b []byte) (n int, err error)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
and as the documentation says, it returns the number of bytes
|
and as the documentation says, it returns the number of bytes
|
||||||
written and a non-nil <code>Error</code> when <code>n</code>
|
written and a non-nil <code>error</code> when <code>n</code>
|
||||||
<code>!=</code> <code>len(b)</code>.
|
<code>!=</code> <code>len(b)</code>.
|
||||||
This is a common style; see the section on error handling for more examples.
|
This is a common style; see the section on error handling for more examples.
|
||||||
</p>
|
</p>
|
||||||
@ -788,7 +788,7 @@ of <code>io.ReadFull</code> that uses them well:
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
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 {
|
for len(buf) > 0 && err == nil {
|
||||||
var nr int
|
var nr int
|
||||||
nr, err = r.Read(buf)
|
nr, err = r.Read(buf)
|
||||||
@ -812,7 +812,7 @@ canonical examples are unlocking a mutex or closing a file.
|
|||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// Contents returns the file's contents as a string.
|
// 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)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -1195,7 +1195,7 @@ limit of how much data to read. Here is the signature of the
|
|||||||
<code>os</code>:
|
<code>os</code>:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func (file *File) Read(buf []byte) (n int, err os.Error)
|
func (file *File) Read(buf []byte) (n int, err error)
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
The method returns the number of bytes read and an error value, if
|
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.
|
|||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
var n int
|
var n int
|
||||||
var err os.Error
|
var err error
|
||||||
for i := 0; i < 32; i++ {
|
for i := 0; i < 32; i++ {
|
||||||
nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
|
nbytes, e := f.Read(buf[i:i+1]) // Read one byte.
|
||||||
if nbytes == 0 || e != nil {
|
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.
|
can appear after the format.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func Printf(format string, v ...interface{}) (n int, errno os.Error) {
|
func Printf(format string, v ...interface{}) (n int, err error) {
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
Within the function <code>Printf</code>, <code>v</code> acts like a variable of type
|
Within the function <code>Printf</code>, <code>v</code> 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 standard <code>Write</code> method, like this,
|
like a standard <code>Write</code> method, like this,
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
func (p *ByteSlice) Write(data []byte) (n int, err os.Error) {
|
func (p *ByteSlice) Write(data []byte) (n int, err error) {
|
||||||
slice := *p
|
slice := *p
|
||||||
// Again as above.
|
// Again as above.
|
||||||
*p = slice
|
*p = slice
|
||||||
@ -2057,11 +2057,11 @@ here are their definitions.
|
|||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
Read(p []byte) (n int, err os.Error)
|
Read(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(p []byte) (n int, err os.Error)
|
Write(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -2123,7 +2123,7 @@ satisfy the <code>io</code> interfaces, we would also need
|
|||||||
to provide forwarding methods, like this:
|
to provide forwarding methods, like this:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
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)
|
return rw.reader.Read(p)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
@ -2575,12 +2575,12 @@ the garbage collector for bookkeeping.
|
|||||||
Library routines must often return some sort of error indication to
|
Library routines must often return some sort of error indication to
|
||||||
the caller. As mentioned earlier, Go's multivalue return makes it
|
the caller. As mentioned earlier, Go's multivalue return makes it
|
||||||
easy to return a detailed error description alongside the normal
|
easy to return a detailed error description alongside the normal
|
||||||
return value. By convention, errors have type <code>os.Error</code>,
|
return value. By convention, errors have type <code>error</code>,
|
||||||
a simple interface.
|
a simple built-in interface.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
type Error interface {
|
type error interface {
|
||||||
String() string
|
Error() string
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -2595,15 +2595,15 @@ For example, <code>os.Open</code> returns an <code>os.PathError</code>.
|
|||||||
type PathError struct {
|
type PathError struct {
|
||||||
Op string // "open", "unlink", etc.
|
Op string // "open", "unlink", etc.
|
||||||
Path string // The associated file.
|
Path string // The associated file.
|
||||||
Error Error // Returned by the system call.
|
Err error // Returned by the system call.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PathError) String() string {
|
func (e *PathError) Error() string {
|
||||||
return e.Op + " " + e.Path + ": " + e.Error.String()
|
return e.Op + " " + e.Path + ": " + e.Err.Error()
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
<code>PathError</code>'s <code>String</code> generates
|
<code>PathError</code>'s <code>Error</code> generates
|
||||||
a string like this:
|
a string like this:
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
@ -2628,7 +2628,7 @@ is "image: unknown format".
|
|||||||
Callers that care about the precise error details can
|
Callers that care about the precise error details can
|
||||||
use a type switch or a type assertion to look for specific
|
use a type switch or a type assertion to look for specific
|
||||||
errors and extract details. For <code>PathErrors</code>
|
errors and extract details. For <code>PathErrors</code>
|
||||||
this might include examining the internal <code>Error</code>
|
this might include examining the internal <code>Err</code>
|
||||||
field for recoverable failures.
|
field for recoverable failures.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -2638,7 +2638,7 @@ for try := 0; try < 2; try++ {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
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.
|
deleteTempFiles() // Recover some space.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -2650,9 +2650,9 @@ for try := 0; try < 2; try++ {
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The usual way to report an error to a caller is to return an
|
The usual way to report an error to a caller is to return an
|
||||||
<code>os.Error</code> as an extra return value. The canonical
|
<code>error</code> as an extra return value. The canonical
|
||||||
<code>Read</code> method is a well-known instance; it returns a byte
|
<code>Read</code> method is a well-known instance; it returns a byte
|
||||||
count and an <code>os.Error</code>. But what if the error is
|
count and an <code>error</code>. But what if the error is
|
||||||
unrecoverable? Sometimes the program simply cannot continue.
|
unrecoverable? Sometimes the program simply cannot continue.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -2768,14 +2768,14 @@ cleanly by calling <code>panic</code>. We can use that idea to
|
|||||||
simplify error handling in complex software. Let's look at an
|
simplify error handling in complex software. Let's look at an
|
||||||
idealized excerpt from the <code>regexp</code> package, which reports
|
idealized excerpt from the <code>regexp</code> package, which reports
|
||||||
parsing errors by calling <code>panic</code> with a local
|
parsing errors by calling <code>panic</code> with a local
|
||||||
<code>Error</code> type. Here's the definition of <code>Error</code>,
|
error type. Here's the definition of <code>Error</code>,
|
||||||
an <code>error</code> method, and the <code>Compile</code> function.
|
an <code>error</code> method, and the <code>Compile</code> function.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
// 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
|
type Error string
|
||||||
func (e Error) String() string {
|
func (e Error) Error() string {
|
||||||
return string(e)
|
return string(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2786,7 +2786,7 @@ func (regexp *Regexp) error(err string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile returns a parsed representation of the regular expression.
|
// 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)
|
regexp = new(Regexp)
|
||||||
// doParse will panic if there is a parse error.
|
// doParse will panic if there is a parse error.
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -2804,7 +2804,7 @@ If <code>doParse</code> panics, the recovery block will set the
|
|||||||
return value to <code>nil</code>—deferred functions can modify
|
return value to <code>nil</code>—deferred functions can modify
|
||||||
named return values. It then will then check, in the assignment
|
named return values. It then will then check, in the assignment
|
||||||
to <code>err</code>, that the problem was a parse error by asserting
|
to <code>err</code>, that the problem was a parse error by asserting
|
||||||
that it has type <code>Error</code>.
|
that it has the local type <code>Error</code>.
|
||||||
If it does not, the type assertion will fail, causing a run-time error
|
If it does not, the type assertion will fail, causing a run-time error
|
||||||
that continues the stack unwinding as though nothing had interrupted
|
that continues the stack unwinding as though nothing had interrupted
|
||||||
it. This check means that if something unexpected happens, such
|
it. This check means that if something unexpected happens, such
|
||||||
@ -2822,7 +2822,7 @@ the parse stack by hand.
|
|||||||
<p>
|
<p>
|
||||||
Useful though this pattern is, it should be used only within a package.
|
Useful though this pattern is, it should be used only within a package.
|
||||||
<code>Parse</code> turns its internal <code>panic</code> calls into
|
<code>Parse</code> turns its internal <code>panic</code> calls into
|
||||||
<code>os.Error</code> values; it does not expose <code>panics</code>
|
<code>error</code> values; it does not expose <code>panics</code>
|
||||||
to its client. That is a good rule to follow.
|
to its client. That is a good rule to follow.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -578,11 +578,13 @@ to see that). Finally, <code>OpenFile</code> returns two values: a pointer to t
|
|||||||
and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
|
and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
|
||||||
be negative and <code>newFile</code> will return <code>nil</code>.
|
be negative and <code>newFile</code> will return <code>nil</code>.
|
||||||
<p>
|
<p>
|
||||||
About those errors: The <code>os</code> library includes a general notion of an error.
|
About those errors: The Go language includes a general notion of an error:
|
||||||
|
a pre-defined type <code>error</code> 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
|
It's a good idea to use its facility in your own interfaces, as we do here, for
|
||||||
consistent error handling throughout Go code. In <code>Open</code> we use a
|
consistent error handling throughout Go code. In <code>Open</code> we use a
|
||||||
conversion to translate Unix's integer <code>errno</code> value into the integer type
|
conversion to translate Unix's integer <code>errno</code> value into the integer type
|
||||||
<code>os.Errno</code>, which implements <code>os.Error</code>.
|
<code>os.Errno</code>, which is an implementation of <code>error</code>
|
||||||
<p>
|
<p>
|
||||||
Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
|
Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
|
||||||
our exercise is emulating. The <code>os</code> package takes the opportunity
|
our exercise is emulating. The <code>os</code> package takes the opportunity
|
||||||
@ -668,7 +670,7 @@ array, not just for <code>structs</code>. We'll see an example with arrays lat
|
|||||||
The <code>String</code> method is so called because of a printing convention we'll
|
The <code>String</code> method is so called because of a printing convention we'll
|
||||||
describe later.
|
describe later.
|
||||||
<p>
|
<p>
|
||||||
The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
|
The methods use the public variable <code>os.EINVAL</code> to return the (<code>error</code>
|
||||||
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
|
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
|
||||||
set of such error values.
|
set of such error values.
|
||||||
<p>
|
<p>
|
||||||
@ -733,13 +735,13 @@ func cat(f *file.File) {
|
|||||||
for {
|
for {
|
||||||
switch nr, er := f.Read(buf[:]); true {
|
switch nr, er := f.Read(buf[:]); true {
|
||||||
case nr < 0:
|
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)
|
os.Exit(1)
|
||||||
case nr == 0: // EOF
|
case nr == 0: // EOF
|
||||||
return
|
return
|
||||||
case nr > 0:
|
case nr > 0:
|
||||||
if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -850,14 +852,14 @@ and use it from within a mostly unchanged <code>cat</code> function:
|
|||||||
for {
|
for {
|
||||||
switch nr, er := r.Read(buf[:]); {
|
switch nr, er := r.Read(buf[:]); {
|
||||||
case nr < 0:
|
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)
|
os.Exit(1)
|
||||||
case nr == 0: // EOF
|
case nr == 0: // EOF
|
||||||
return
|
return
|
||||||
case nr > 0:
|
case nr > 0:
|
||||||
nw, ew := file.Stdout.Write(buf[0:nr])
|
nw, ew := file.Stdout.Write(buf[0:nr])
|
||||||
if nw != 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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -990,7 +992,7 @@ implements <code>Printf</code>, <code>Fprintf</code>, and so on.
|
|||||||
Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
|
Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
|
||||||
<p>
|
<p>
|
||||||
<pre>
|
<pre>
|
||||||
Printf(format string, v ...interface{}) (n int, errno os.Error)
|
Printf(format string, v ...interface{}) (n int, errno error)
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
The token <code>...</code> introduces a variable-length argument list that in C would
|
The token <code>...</code> introduces a variable-length argument list that in C would
|
||||||
@ -1127,6 +1129,21 @@ If the value does not satisfy the interface, <code>ok</code> will be false.
|
|||||||
In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
|
In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
|
||||||
to interfaces describing simple method sets like this.
|
to interfaces describing simple method sets like this.
|
||||||
<p>
|
<p>
|
||||||
|
A related interface is that defined by the <code>error</code> builtin type, which is just
|
||||||
|
<p>
|
||||||
|
<pre>
|
||||||
|
type error interface {
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Other than the method name (<code>Error</code> vs. <code>String</code>), this looks like
|
||||||
|
a <code>Stringer</code>; the different name guarantees that types that implement <code>Stringer</code>
|
||||||
|
don't accidentally satisfy the <code>error</code> interface.
|
||||||
|
Naturally, <code>Printf</code> and its relatives recognize the <code>error</code> interface,
|
||||||
|
just as they do <code>Stringer</code>,
|
||||||
|
so it's trivial to print an error as a string.
|
||||||
|
<p>
|
||||||
One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
|
One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
|
||||||
etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
|
etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
|
||||||
not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
|
not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
|
||||||
@ -1134,7 +1151,7 @@ interface type defined in the <code>io</code> library:
|
|||||||
<p>
|
<p>
|
||||||
<pre>
|
<pre>
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(p []byte) (n int, err os.Error)
|
Write(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
|
@ -490,11 +490,13 @@ to see that). Finally, <code>OpenFile</code> returns two values: a pointer to t
|
|||||||
and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
|
and the error. If <code>syscall.Open</code> fails, the file descriptor <code>r</code> will
|
||||||
be negative and <code>newFile</code> will return <code>nil</code>.
|
be negative and <code>newFile</code> will return <code>nil</code>.
|
||||||
<p>
|
<p>
|
||||||
About those errors: The <code>os</code> library includes a general notion of an error.
|
About those errors: The Go language includes a general notion of an error:
|
||||||
|
a pre-defined type <code>error</code> 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
|
It's a good idea to use its facility in your own interfaces, as we do here, for
|
||||||
consistent error handling throughout Go code. In <code>Open</code> we use a
|
consistent error handling throughout Go code. In <code>Open</code> we use a
|
||||||
conversion to translate Unix's integer <code>errno</code> value into the integer type
|
conversion to translate Unix's integer <code>errno</code> value into the integer type
|
||||||
<code>os.Errno</code>, which implements <code>os.Error</code>.
|
<code>os.Errno</code>, which is an implementation of <code>error</code>
|
||||||
<p>
|
<p>
|
||||||
Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
|
Why <code>OpenFile</code> and not <code>Open</code>? To mimic Go's <code>os</code> package, which
|
||||||
our exercise is emulating. The <code>os</code> package takes the opportunity
|
our exercise is emulating. The <code>os</code> package takes the opportunity
|
||||||
@ -527,7 +529,7 @@ array, not just for <code>structs</code>. We'll see an example with arrays lat
|
|||||||
The <code>String</code> method is so called because of a printing convention we'll
|
The <code>String</code> method is so called because of a printing convention we'll
|
||||||
describe later.
|
describe later.
|
||||||
<p>
|
<p>
|
||||||
The methods use the public variable <code>os.EINVAL</code> to return the (<code>os.Error</code>
|
The methods use the public variable <code>os.EINVAL</code> to return the (<code>error</code>
|
||||||
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
|
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
|
||||||
set of such error values.
|
set of such error values.
|
||||||
<p>
|
<p>
|
||||||
@ -692,7 +694,7 @@ implements <code>Printf</code>, <code>Fprintf</code>, and so on.
|
|||||||
Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
|
Within the <code>fmt</code> package, <code>Printf</code> is declared with this signature:
|
||||||
<p>
|
<p>
|
||||||
<pre>
|
<pre>
|
||||||
Printf(format string, v ...interface{}) (n int, errno os.Error)
|
Printf(format string, v ...interface{}) (n int, errno error)
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
The token <code>...</code> introduces a variable-length argument list that in C would
|
The token <code>...</code> introduces a variable-length argument list that in C would
|
||||||
@ -801,6 +803,21 @@ If the value does not satisfy the interface, <code>ok</code> will be false.
|
|||||||
In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
|
In this snippet the name <code>Stringer</code> follows the convention that we add ''[e]r''
|
||||||
to interfaces describing simple method sets like this.
|
to interfaces describing simple method sets like this.
|
||||||
<p>
|
<p>
|
||||||
|
A related interface is that defined by the <code>error</code> builtin type, which is just
|
||||||
|
<p>
|
||||||
|
<pre>
|
||||||
|
type error interface {
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Other than the method name (<code>Error</code> vs. <code>String</code>), this looks like
|
||||||
|
a <code>Stringer</code>; the different name guarantees that types that implement <code>Stringer</code>
|
||||||
|
don't accidentally satisfy the <code>error</code> interface.
|
||||||
|
Naturally, <code>Printf</code> and its relatives recognize the <code>error</code> interface,
|
||||||
|
just as they do <code>Stringer</code>,
|
||||||
|
so it's trivial to print an error as a string.
|
||||||
|
<p>
|
||||||
One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
|
One last wrinkle. To complete the suite, besides <code>Printf</code> etc. and <code>Sprintf</code>
|
||||||
etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
|
etc., there are also <code>Fprintf</code> etc. Unlike in C, <code>Fprintf</code>'s first argument is
|
||||||
not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
|
not a file. Instead, it is a variable of type <code>io.Writer</code>, which is an
|
||||||
@ -808,7 +825,7 @@ interface type defined in the <code>io</code> library:
|
|||||||
<p>
|
<p>
|
||||||
<pre>
|
<pre>
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
Write(p []byte) (n int, err os.Error)
|
Write(p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
|
@ -17,13 +17,13 @@ func cat(f *file.File) {
|
|||||||
for {
|
for {
|
||||||
switch nr, er := f.Read(buf[:]); true {
|
switch nr, er := f.Read(buf[:]); true {
|
||||||
case nr < 0:
|
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)
|
os.Exit(1)
|
||||||
case nr == 0: // EOF
|
case nr == 0: // EOF
|
||||||
return
|
return
|
||||||
case nr > 0:
|
case nr > 0:
|
||||||
if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,14 @@ func cat(r reader) {
|
|||||||
for {
|
for {
|
||||||
switch nr, er := r.Read(buf[:]); {
|
switch nr, er := r.Read(buf[:]); {
|
||||||
case nr < 0:
|
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)
|
os.Exit(1)
|
||||||
case nr == 0: // EOF
|
case nr == 0: // EOF
|
||||||
return
|
return
|
||||||
case nr > 0:
|
case nr > 0:
|
||||||
nw, ew := file.Stdout.Write(buf[0:nr])
|
nw, ew := file.Stdout.Write(buf[0:nr])
|
||||||
if nw != 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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user