From: Rob Pike Date: Mon, 12 Oct 2009 21:51:12 +0000 (-0700) Subject: printing and maps X-Git-Tag: weekly.2009-11-06~340 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9dfe40441ec58c1d18e87a544fcdb98b342553c2;p=gostls13.git printing and maps R=rsc,gri DELTA=228 (223 added, 1 deleted, 4 changed) OCL=35617 CL=35619 --- diff --git a/doc/effective_go.html b/doc/effective_go.html index af1febe2c8..ec40ce87ab 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -1,6 +1,6 @@ - +

Introduction

@@ -34,7 +34,7 @@ should read first.

Examples

-The Go package sources +The Go package sources are intended to serve not only as the core library but also as examples of how to use the language. @@ -97,7 +97,6 @@ type T struct {

All code in the libraries has been formatted with gofmt. -TODO

@@ -108,7 +107,7 @@ Some formatting details remain. Very briefly:
Indentation
We use tabs for indentation and gofmt emits them by default. - Use spaces if you must. + Use spaces only if you must.
Line length
@@ -118,7 +117,7 @@ Some formatting details remain. Very briefly:
Parentheses
Go needs fewer parentheses: control structures (if, - for, switch) do not have parentheses in + for, switch) do not require parentheses in their syntax. Also, the operator precedence hierarchy is shorter and clearer, so
@@ -1059,8 +1058,231 @@ structure holding the pointer, length, and capacity) is passed by value.
 
 
 

Maps

+ +

+Maps are a convenient and powerful built-in data structure to associate +values of different types. +The key can be of type that implements equality, such as integers, +floats, strings, pointers, and interfaces (as long as the dynamic type +supports equality), but not structs, arrays or slices +because those types do not have equality defined upon them. +Like slices, maps are a reference type. If you pass a map to a function +that changes the contents of the map, the changes will be visible +in the caller. +

+

+Maps can be constructed using the usual composite literal syntax +with colon-separated key-value pairs, +so it's easy to build them during initialization. +

+
+var timeZone = map[string] int {
+	"UTC":  0*60*60,
+	"EST": -5*60*60,
+	"CST": -6*60*60,
+	"MST": -7*60*60,
+	"PST": -8*60*60,
+}
+
+

+Assigning and fetching map values looks syntactically just like +doing the same for arrays except that the index doesn't need to +be an integer. An attempt to fetch a map value with a key that +is not present in the map will cause the program to crash, but +there is a way to do so safely using a multiple assignment. +

+
+var seconds int;
+var ok bool;
+seconds, ok = timeZone[tz]
+
+

+For obvious reasons this is called the “comma ok” idiom. +In this example, if tz is present, seconds +will be set appropriately and ok will be true; if not, +seconds will be set to zero and ok will +be false. +Here's a function that puts it together: +

+
+func offset(tz string) int {
+	if seconds, ok := timeZone[tz]; ok {
+		return seconds
+	}
+	log.Stderr("unknown time zone", tz);
+	return 0;
+}
+
+

+To test for presence in the map without worrying about the actual value, +you can use the blank identifier, a simple underscore (_). +The blank identifier can be assigned or declared with any value of any type, with the +value discarded harmlessly. For testing presence in a map, use the blank +identifier in place of the usual variable for the value. +

+
+_, present := timeZone[tz];
+
+

+To delete a map entry, turn the multiple assignment around by placing +an extra boolean on the right; if the boolean is false, the entry +is deleted. It's safe to do this even if the key is already absent +from the map. +

+
+timeZone["PDT"] = 0, false;  // Now on Standard Time
+

Printing

+

+Formatted printing in Go uses a style similar to C's printf +family but is richer and more general. The functions live in the fmt +package and have capitalized names: fmt.Printf, fmt.Fprintf, +fmt.Sprintf and so on. The string functions (Sprintf etc.) +return a string rather than filling in a provided buffer. +

+

+You don't need to provide a format string. For each of Printf, +fmt.Fprintf and fmt.Sprintf there is another pair +of functions, for instance Print and Println. +These functions do not take a format string but instead generate a default +format for each argument. The ln version also inserts a blank +between arguments if neither is a string and appends a newline to the output. +In this example each line produces the same output. +

+
+fmt.Printf("Hello %d\n", 23);
+fmt.Fprint(os.Stdout, "Hello ", 23, "\n");
+fmt.Println(fmt.Sprint("Hello ", 23));
+
+

+Recall that fmt.Fprint and friends take as a first argument any object +that implements the io.Writer interface; the variables os.Stdout +and os.Stderr are familiar instances. +

+

+Here things start to diverge from C. First, the numeric formats such as %d +do not take flags for signedness or size; instead, the printing routines use the +type of the argument to decide these properties. +

+
+var x uint64 = 1<<64 - 1;
+fmt.Printf("%d %x; %d %x\n", x, x, int64(x), int64(x));
+
+

+prints +

+
+18446744073709551615 ffffffffffffffff; -1 -1
+
+

+If you just want the default conversion, such as decimal for integers, you can use +the catchall format %v (for “value”); the result is exactly +what Print and Println would produce. +Moreover, that format can print any value, even arrays, structs, and +maps. Here is a print statement for the time zone map defined in the previous section. +

+
+fmt.Printf("%v\n", timeZone);  // or just fmt.Println(timeZone);
+
+

+which gives output +

+
+map[CST:-21600 PST:-28800 EST:-18000 UTC:0 MST:-25200]
+
+

+For maps the keys may be output in any order, of course. +When printing a struct, the modified format %+v annotates the +fields of the structure with their names, and for any value the alternate +format %#v prints the value in full Go syntax. +

+
+type T struct {
+	a int;
+	b float;
+	c string;
+}
+t := &T{ 7, -2.35, "abc\tdef" };
+fmt.Printf("%v\n", t);
+fmt.Printf("%+v\n", t);
+fmt.Printf("%#v\n", t);
+fmt.Printf("%#v\n", timeZone);
+
+

+prints +

+
+&{7 -2.35 abc   def}
+&{a:7 b:-2.35 c:abc     def}
+&main.T{a:7, b:-2.35, c:"abc\tdef"}
+map[string] int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}
+
+

+(Note the ampersands.) +That quoted string format is also available through %q when +applied to a value of type string or []byte; +the alternate format %#q will use backquotes instead if possible. +Also, %x works on strings and arrays of bytes as well as on integers, +generating a long hexadecimal string, and with +a space in the format (% x) it puts spaces between the bytes. +

+

+Another handy format is %T, which prints the type of a value. +

+fmt.Printf("%T\n", timeZone);
+
+

+prints +

+
+map[string] int
+
+

+If you want to control the default format for a custom type, all that's required is to define +a method String() string on the type. (Methods are the subject of the next +section.) For our simple type T, that might look like this. +

+
+func (t *T) String() string {
+	return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c);
+}
+fmt.Printf("%v\n", t);
+
+

+to print in the format +

+
+7/-2.35/"abc\tdef"
+
+

+Our String() method is able to call Sprintf because the +print routines are fully reentrant and can be used recursively. +We can even go one step further and pass a print routine's arguments directly to another such routine. +The signature of Printf uses the ... +type for its final argument to specify that an arbitrary number of parameters can appear +after the format. +

+
+func Printf(format string, v ...) (n int, errno os.Error) {
+
+

+Within the function Printf, v is a variable that can be passed, +for instance, to another print routine. Here is the implementation of the +function log.Stderr we used above. It passes its arguments directly to +fmt.Sprintln for the actual formatting. +

+
+// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr).
+func Stderr(v ...) {
+	stderr.Output(2, fmt.Sprintln(v));  // Output takes parameters (int, string)
+}
+
+

+There's even more to printing than we've covered here. See the godoc documentation +for package fmt for the details. +

+

Methods

Pointers vs. Values

@@ -1112,7 +1334,7 @@ print into one:

 	var b ByteSlice;
-	fmt.Fprintf(&b, "This minute has %d seconds\n", 61);
+	fmt.Fprintf(&b, "This hour has %d days\n", 7);
 

Notice that we must pass the address of a ByteSlice @@ -1159,7 +1381,7 @@ Implementations of os.Error should describe the error and provide context. For example, os.Open returns an os.PathError: -/src/pkg/os/file.go: +http://go/godoc/src/pkg/os/file.go:

 // PathError records an error and the operation and
 // file path that caused it.