Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
68050ac7
Commit
68050ac7
authored
Nov 01, 2011
by
Rob Pike
Committed by
Russ Cox
Nov 01, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tutorial,effective_go: prepare for error change
R=adg, rsc CC=golang-dev
https://golang.org/cl/5316068
parent
451a1fa4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
118 additions
and
84 deletions
+118
-84
doc/effective_go.html
doc/effective_go.html
+33
-33
doc/effective_go.tmpl
doc/effective_go.tmpl
+33
-33
doc/go_tutorial.html
doc/go_tutorial.html
+26
-9
doc/go_tutorial.tmpl
doc/go_tutorial.tmpl
+22
-5
doc/progs/cat.go
doc/progs/cat.go
+2
-2
doc/progs/cat_rot13.go
doc/progs/cat_rot13.go
+2
-2
No files found.
doc/effective_go.html
View file @
68050ac7
...
@@ -221,7 +221,7 @@ starts with the name being declared.
...
@@ -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, err
or os.E
rror) {
func Compile(str string) (regexp *Regexp, err
e
rror) {
</pre>
</pre>
<p>
<p>
...
@@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
...
@@ -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:
...
@@ -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
E
rror)
func (file *File) Write(b []byte) (n int, err
e
rror)
</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>
E
rror
</code>
when
<code>
n
</code>
written and a non-nil
<code>
e
rror
</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:
...
@@ -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.E
rror) {
func ReadFull(r Reader, buf []byte) (n int, err
e
rror) {
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.
...
@@ -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.E
rror) {
func Contents(filename string) (string,
e
rror) {
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
...
@@ -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.E
rror)
func (file *File) Read(buf []byte) (n int, err
e
rror)
</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.
...
@@ -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.E
rror
var err
e
rror
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
...
@@ -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, err
no os.E
rror) {
func Printf(format string, v ...interface{}) (n int, err
e
rror) {
</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
...
@@ -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.E
rror) {
func (p *ByteSlice) Write(data []byte) (n int, err
e
rror) {
slice := *p
slice := *p
// Again as above.
// Again as above.
*p = slice
*p = slice
...
@@ -2119,11 +2119,11 @@ here are their definitions.
...
@@ -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.E
rror)
Read(p []byte) (n int, err
e
rror)
}
}
type Writer interface {
type Writer interface {
Write(p []byte) (n int, err
os.E
rror)
Write(p []byte) (n int, err
e
rror)
}
}
</pre>
</pre>
<p>
<p>
...
@@ -2185,7 +2185,7 @@ satisfy the <code>io</code> interfaces, we would also need
...
@@ -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.E
rror) {
func (rw *ReadWriter) Read(p []byte) (n int, err
e
rror) {
return rw.reader.Read(p)
return rw.reader.Read(p)
}
}
</pre>
</pre>
...
@@ -2637,12 +2637,12 @@ the garbage collector for bookkeeping.
...
@@ -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.E
rror
</code>
,
return value. By convention, errors have type
<code>
e
rror
</code>
,
a simple interface.
a simple
built-in
interface.
</p>
</p>
<pre>
<pre>
type
E
rror interface {
type
e
rror 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>.
...
@@ -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.
Err
or 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.Err
or.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".
...
@@ -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>
Err
or
</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++ {
...
@@ -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.Err
or
== 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++ {
...
@@ -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.E
rror
</code>
as an extra return value. The canonical
<code>
e
rror
</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.E
rror
</code>
. But what if the error is
count and an
<code>
e
rror
</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
...
@@ -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) {
...
@@ -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.E
rror) {
func Compile(str string) (regexp *Regexp, err
e
rror) {
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
...
@@ -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 t
he local t
ype
<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.
...
@@ -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.E
rror
</code>
values; it does not expose
<code>
panics
</code>
<code>
e
rror
</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>
...
...
doc/effective_go.tmpl
View file @
68050ac7
...
@@ -221,7 +221,7 @@ starts with the name being declared.
...
@@ -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, err
or os.E
rror) {
func Compile(str string) (regexp *Regexp, err
e
rror) {
</pre>
</pre>
<p>
<p>
...
@@ -233,9 +233,9 @@ Since the whole declaration is presented, such a comment can often be perfunctor
...
@@ -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:
...
@@ -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
E
rror)
func (file *File) Write(b []byte) (n int, err
e
rror)
</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>
E
rror</code> when <code>n</code>
written and a non-nil <code>
e
rror</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:
...
@@ -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
.
E
rror
)
{
func
ReadFull
(
r
Reader
,
buf
[]
byte
)
(
n
int
,
err
e
rror
)
{
for
len
(
buf
)
&
gt
;
0
&
amp
;&
amp
;
err
==
nil
{
for
len
(
buf
)
&
gt
;
0
&
amp
;&
amp
;
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.
...
@@ -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.E
rror) {
func Contents(filename string) (string,
e
rror) {
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
...
@@ -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.E
rror)
func (file *File) Read(buf []byte) (n int, err
e
rror)
</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.
...
@@ -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.E
rror
var err
e
rror
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
...
@@ -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, err
no os.E
rror) {
func Printf(format string, v ...interface{}) (n int, err
e
rror) {
</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
...
@@ -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.E
rror) {
func (p *ByteSlice) Write(data []byte) (n int, err
e
rror) {
slice := *p
slice := *p
// Again as above.
// Again as above.
*p = slice
*p = slice
...
@@ -2057,11 +2057,11 @@ here are their definitions.
...
@@ -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
.
E
rror
)
Read
(
p
[]
byte
)
(
n
int
,
err
e
rror
)
}
}
type
Writer
interface
{
type
Writer
interface
{
Write
(
p
[]
byte
)
(
n
int
,
err
os
.
E
rror
)
Write
(
p
[]
byte
)
(
n
int
,
err
e
rror
)
}
}
</
pre
>
</
pre
>
<
p
>
<
p
>
...
@@ -2123,7 +2123,7 @@ satisfy the <code>io</code> interfaces, we would also need
...
@@ -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.E
rror) {
func (rw *ReadWriter) Read(p []byte) (n int, err
e
rror) {
return rw.reader.Read(p)
return rw.reader.Read(p)
}
}
</pre>
</pre>
...
@@ -2575,12 +2575,12 @@ the garbage collector for bookkeeping.
...
@@ -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
.
E
rror
</
code
>,
return
value
.
By
convention
,
errors
have
type
<
code
>
e
rror
</
code
>,
a
simple
interface
.
a
simple
built
-
in
interface
.
</
p
>
</
p
>
<
pre
>
<
pre
>
type
E
rror
interface
{
type
e
rror
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>.
...
@@ -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
.
Err
or
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
.
Err
or
.
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".
...
@@ -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>Err
or
</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++ {
...
@@ -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.Err
or
== 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++ {
...
@@ -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.E
rror</code> as an extra return value. The canonical
<code>
e
rror</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.E
rror</code>. But what if the error is
count and an <code>
e
rror</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
...
@@ -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) {
...
@@ -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
.
E
rror
)
{
func
Compile
(
str
string
)
(
regexp
*
Regexp
,
err
e
rror
)
{
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
...
@@ -2804,7 +2804,7 @@ If <code>doParse</code> panics, the recovery block will set the
return
value
to
<
code
>
nil
</
code
>&
mdash
;
deferred
functions
can
modify
return
value
to
<
code
>
nil
</
code
>&
mdash
;
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
t
he
local
t
ype
<
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.
...
@@ -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
.
E
rror
</
code
>
values
;
it
does
not
expose
<
code
>
panics
</
code
>
<
code
>
e
rror
</
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
>
...
...
doc/go_tutorial.html
View file @
68050ac7
...
@@ -578,11 +578,13 @@ to see that). Finally, <code>OpenFile</code> returns two values: a pointer to t
...
@@ -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 i
mplements
<code>
os.Error
</code>
.
<code>
os.Errno
</code>
, which i
s 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
...
@@ -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.E
rror
</code>
The methods use the public variable
<code>
os.EINVAL
</code>
to return the (
<code>
e
rror
</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) {
...
@@ -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:
...
@@ -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.
...
@@ -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.E
rror)
Printf(format string, v ...interface{}) (n int, errno
e
rror)
</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.
...
@@ -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:
...
@@ -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.E
rror)
Write(p []byte) (n int, err
e
rror)
}
}
</pre>
</pre>
<p>
<p>
...
...
doc/go_tutorial.tmpl
View file @
68050ac7
...
@@ -490,11 +490,13 @@ to see that). Finally, <code>OpenFile</code> returns two values: a pointer to t
...
@@ -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 i
mplements <code>os.Error</code>.
<code>os.Errno</code>, which i
s 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
...
@@ -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.E
rror</code>
The methods use the public variable <code>os.EINVAL</code> to return the (<code>
e
rror</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.
...
@@ -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
.
E
rror
)
Printf
(
format
string
,
v
...
interface
{})
(
n
int
,
errno
e
rror
)
</
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.
...
@@ -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:
...
@@ -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.E
rror)
Write(p []byte) (n int, err
e
rror)
}
}
</pre>
</pre>
<p>
<p>
...
...
doc/progs/cat.go
View file @
68050ac7
...
@@ -17,13 +17,13 @@ func cat(f *file.File) {
...
@@ -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
)
}
}
}
}
...
...
doc/progs/cat_rot13.go
View file @
68050ac7
...
@@ -59,14 +59,14 @@ func cat(r reader) {
...
@@ -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
)
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment