From d2228692b279827a61100bbf8350688fe230448a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 12 Oct 2009 21:18:23 -0700 Subject: [PATCH] type switches errors R=rsc DELTA=150 (74 added, 34 deleted, 42 changed) OCL=35647 CL=35650 --- doc/effective_go.html | 170 ++++++++++++++++++++++++++---------------- 1 file changed, 105 insertions(+), 65 deletions(-) diff --git a/doc/effective_go.html b/doc/effective_go.html index ec40ce87ab..73b91ca80f 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -628,6 +628,28 @@ func Compare(a, b []byte) int { } +

+A switch can also be used to discover the dynamic type of an interface +variable. Such a type switch uses the syntax of a type +assertion with the keyword type inside the parentheses. +If the switch declares a variable in the expression, the variable will +have the corresponding type in each clause. +

+
+switch t := interfaceValue.(type) {
+default:
+	fmt.Printf("unexpected type");
+case bool:
+	fmt.Printf("boolean %t\n", t);
+case int:
+	fmt.Printf("integer %d\n", t);
+case *bool:
+	fmt.Printf("pointer to boolean %t\n", *t);
+case *int:
+	fmt.Printf("pointer to integer %d\n", *t);
+}
+
+

Functions

Multiple return values

@@ -1350,75 +1372,124 @@ By the way, the idea of using Write on a slice of bytes is implemented by bytes.Buffer.

-

More to come

+

Interfaces

-Implementations of os.Error should -describe the error and provide context. -For example, os.Open returns an os.PathError: +

Errors

-http://go/godoc/src/pkg/os/file.go: +

+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 type os.Error, +a simple interface. +

+
+type Error interface {
+    String() string;
+}
+
+

+A library writer is free to implement this interface with a +richer model under the covers, making it possible not only +to see the error but also to provide some context. +For example, os.Open returns an os.PathError. +

 // PathError records an error and the operation and
 // file path that caused it.
 type PathError struct {
-	Op string;
-	Path string;
-	Error Error;
+	Op string;    // "open", "unlink", etc.
+	Path string;  // The associated file.
+	Error Error;  // Returned by the system call.
 }
 
 func (e *PathError) String() string {
-	return e.Op + " " + e.Path + ": " + e.Error.String();
+	return e.Op + " " + e.Path + ": " + e.Error.String();
 }
 
-

-PathError's String formats -the error nicely, including the operation and file name -tha failed; just printing the error generates a -message, such as +PathError's String generates +a string like this:

 open /etc/passwx: no such file or directory
 

-that is useful even if printed far from the call that -triggered it. +Such an error, which includes the problematic file name, the +operation, and the operating system error it triggered, is useful even +if printed far from the call that caused it; +it is much more informative than the plain +"no such file or directory".

Callers that care about the precise error details can -use a type switch or a type guard to look for specific +use a type switch or a type assertion to look for specific errors and extract details. For PathErrors this might include examining the internal Error -to see if it is os.EPERM or os.ENOENT, -for instance. +field for recoverable failures.

+
+for try := 0; try < 2; try++ {
+	file, err := os.Open(filename, os.O_RDONLY, 0);
+	if err == nil {
+		return
+	}
+	if e, ok := err.(*os.PathError); ok && e.Error == os.ENOSPC {
+		deleteTempFiles();  // Recover some space.
+		continue
+	}
+	return
+}
+
+ +

Testing

+ +

More to come

+ +