Commit 46f482a2 authored by Rob Pike's avatar Rob Pike

docs: remove some prose-unworthy empty parentheses.

In our evolving style, prose should name a function "f" not "f()".

R=gri, rsc
CC=golang-dev
https://golang.org/cl/4550075
parent bdbe0dec
...@@ -935,13 +935,14 @@ example of its possibilities. ...@@ -935,13 +935,14 @@ example of its possibilities.
<h2 id="data">Data</h2> <h2 id="data">Data</h2>
<h3 id="allocation_new">Allocation with <code>new()</code></h3> <h3 id="allocation_new">Allocation with <code>new</code></h3>
<p> <p>
Go has two allocation primitives, <code>new()</code> and <code>make()</code>. Go has two allocation primitives, the built-in functions
<code>new</code> and <code>make</code>.
They do different things and apply to different types, which can be confusing, They do different things and apply to different types, which can be confusing,
but the rules are simple. but the rules are simple.
Let's talk about <code>new()</code> first. Let's talk about <code>new</code> first.
It's a built-in function essentially the same as its namesakes It's a built-in function essentially the same as its namesakes
in other languages: <code>new(T)</code> allocates zeroed storage for a new item of type in other languages: <code>new(T)</code> allocates zeroed storage for a new item of type
<code>T</code> and returns its address, a value of type <code>*T</code>. <code>T</code> and returns its address, a value of type <code>*T</code>.
...@@ -950,9 +951,9 @@ In Go terminology, it returns a pointer to a newly allocated zero value of type ...@@ -950,9 +951,9 @@ In Go terminology, it returns a pointer to a newly allocated zero value of type
</p> </p>
<p> <p>
Since the memory returned by <code>new()</code> is zeroed, it's helpful to arrange that the Since the memory returned by <code>new</code> is zeroed, it's helpful to arrange that the
zeroed object can be used without further initialization. This means a user of zeroed object can be used without further initialization. This means a user of
the data structure can create one with <code>new()</code> and get right to the data structure can create one with <code>new</code> and get right to
work. work.
For example, the documentation for <code>bytes.Buffer</code> states that For example, the documentation for <code>bytes.Buffer</code> states that
"the zero value for <code>Buffer</code> is an empty buffer ready to use." "the zero value for <code>Buffer</code> is an empty buffer ready to use."
...@@ -1065,7 +1066,7 @@ s := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"} ...@@ -1065,7 +1066,7 @@ s := []string {Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"} m := map[int]string{Enone: "no error", Eio: "Eio", Einval: "invalid argument"}
</pre> </pre>
<h3 id="allocation_make">Allocation with <code>make()</code></h3> <h3 id="allocation_make">Allocation with <code>make</code></h3>
<p> <p>
Back to allocation. Back to allocation.
...@@ -1099,8 +1100,8 @@ In contrast, <code>new([]int)</code> returns a pointer to a newly allocated, zer ...@@ -1099,8 +1100,8 @@ In contrast, <code>new([]int)</code> returns a pointer to a newly allocated, zer
structure, that is, a pointer to a <code>nil</code> slice value. structure, that is, a pointer to a <code>nil</code> slice value.
<p> <p>
These examples illustrate the difference between <code>new()</code> and These examples illustrate the difference between <code>new</code> and
<code>make()</code>. <code>make</code>.
</p> </p>
<pre> <pre>
...@@ -1116,9 +1117,9 @@ v := make([]int, 100) ...@@ -1116,9 +1117,9 @@ v := make([]int, 100)
</pre> </pre>
<p> <p>
Remember that <code>make()</code> applies only to maps, slices and channels Remember that <code>make</code> applies only to maps, slices and channels
and does not return a pointer. and does not return a pointer.
To obtain an explicit pointer allocate with <code>new()</code>. To obtain an explicit pointer allocate with <code>new</code>.
</p> </p>
<h3 id="arrays">Arrays</h3> <h3 id="arrays">Arrays</h3>
...@@ -1473,7 +1474,7 @@ map[string] int ...@@ -1473,7 +1474,7 @@ map[string] int
</pre> </pre>
<p> <p>
If you want to control the default format for a custom type, all that's required is to define If you want to control the default format for a custom type, all that's required is to define
a method <code>String() string</code> on the type. a method with the signature <code>String() string</code> on the type.
For our simple type <code>T</code>, that might look like this. For our simple type <code>T</code>, that might look like this.
</p> </p>
<pre> <pre>
...@@ -1495,7 +1496,7 @@ that's more efficient and idiomatic for struct types. ...@@ -1495,7 +1496,7 @@ that's more efficient and idiomatic for struct types.
See the section below on <a href="#pointers_vs_values">pointers vs. value receivers</a> for more information.) See the section below on <a href="#pointers_vs_values">pointers vs. value receivers</a> for more information.)
</p> </p>
<p> <p>
Our <code>String()</code> method is able to call <code>Sprintf</code> because the Our <code>String</code> method is able to call <code>Sprintf</code> because the
print routines are fully reentrant and can be used recursively. 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. We can even go one step further and pass a print routine's arguments directly to another such routine.
The signature of <code>Printf</code> uses the type <code>...interface{}</code> The signature of <code>Printf</code> uses the type <code>...interface{}</code>
...@@ -1683,19 +1684,20 @@ var ( ...@@ -1683,19 +1684,20 @@ var (
<h3 id="init">The init function</h3> <h3 id="init">The init function</h3>
<p> <p>
Finally, each source file can define its own <code>init()</code> function to Finally, each source file can define its own niladic <code>init</code> function to
set up whatever state is required. The only restriction is that, although set up whatever state is required. (Actually each file can have multiple
<code>init</code> functions.) The only restriction is that, although
goroutines can be launched during initialization, they will not begin goroutines can be launched during initialization, they will not begin
execution until it completes; initialization always runs as a single thread execution until it completes; initialization always runs as a single thread
of execution. of execution.
And finally means finally: <code>init()</code> is called after all the And finally means finally: <code>init</code> is called after all the
variable declarations in the package have evaluated their initializers, variable declarations in the package have evaluated their initializers,
and those are evaluated only after all the imported packages have been and those are evaluated only after all the imported packages have been
initialized. initialized.
</p> </p>
<p> <p>
Besides initializations that cannot be expressed as declarations, Besides initializations that cannot be expressed as declarations,
a common use of <code>init()</code> functions is to verify or repair a common use of <code>init</code> functions is to verify or repair
correctness of the program state before real execution begins. correctness of the program state before real execution begins.
</p> </p>
...@@ -1899,7 +1901,7 @@ on every instance of a common method. ...@@ -1899,7 +1901,7 @@ on every instance of a common method.
In such cases, the constructor should return an interface value In such cases, the constructor should return an interface value
rather than the implementing type. rather than the implementing type.
As an example, in the hash libraries As an example, in the hash libraries
both <code>crc32.NewIEEE()</code> and <code>adler32.New()</code> both <code>crc32.NewIEEE</code> and <code>adler32.New</code>
return the interface type <code>hash.Hash32</code>. return the interface type <code>hash.Hash32</code>.
Substituting the CRC-32 algorithm for Adler-32 in a Go program Substituting the CRC-32 algorithm for Adler-32 in a Go program
requires only changing the constructor call; requires only changing the constructor call;
......
<!-- title The Go Programming Language Specification --> <!-- title The Go Programming Language Specification -->
<!-- subtitle Version of May 23, 2011 --> <!-- subtitle Version of May 24, 2011 -->
<!-- <!--
TODO TODO
...@@ -821,7 +821,7 @@ make([]T, length, capacity) ...@@ -821,7 +821,7 @@ make([]T, length, capacity)
</pre> </pre>
<p> <p>
The <code>make()</code> call allocates a new, hidden array to which the returned A call to <code>make</code> allocates a new, hidden array to which the returned
slice value refers. That is, executing slice value refers. That is, executing
</p> </p>
...@@ -4931,7 +4931,7 @@ func main() { ...@@ -4931,7 +4931,7 @@ func main() {
<h3 id="The_zero_value">The zero value</h3> <h3 id="The_zero_value">The zero value</h3>
<p> <p>
When memory is allocated to store a value, either through a declaration When memory is allocated to store a value, either through a declaration
or <code>make()</code> or <code>new()</code> call, or a call of <code>make</code> or <code>new</code>,
and no explicit initialization is provided, the memory is and no explicit initialization is provided, the memory is
given a default initialization. Each element of such a value is given a default initialization. Each element of such a value is
set to the <i>zero value</i> for its type: <code>false</code> for booleans, set to the <i>zero value</i> for its type: <code>false</code> for booleans,
...@@ -4989,7 +4989,7 @@ func init() ...@@ -4989,7 +4989,7 @@ func init()
<p> <p>
defined in its source. defined in its source.
A package may contain multiple A package may contain multiple
<code>init()</code> functions, even <code>init</code> functions, even
within a single source file; they execute within a single source file; they execute
in unspecified order. in unspecified order.
</p> </p>
...@@ -5019,8 +5019,8 @@ program is complete. Therefore, all initialization code is run in a single ...@@ -5019,8 +5019,8 @@ program is complete. Therefore, all initialization code is run in a single
goroutine. goroutine.
</p> </p>
<p> <p>
An <code>init()</code> function cannot be referred to from anywhere An <code>init</code> function cannot be referred to from anywhere
in a program. In particular, <code>init()</code> cannot be called explicitly, in a program. In particular, <code>init</code> cannot be called explicitly,
nor can a pointer to <code>init</code> be assigned to a function variable. nor can a pointer to <code>init</code> be assigned to a function variable.
</p> </p>
<p> <p>
......
...@@ -341,7 +341,7 @@ Using slices one can write this function (from <code>sum.go</code>): ...@@ -341,7 +341,7 @@ Using slices one can write this function (from <code>sum.go</code>):
15 } 15 }
</pre> </pre>
<p> <p>
Note how the return type (<code>int</code>) is defined for <code>sum()</code> by stating it Note how the return type (<code>int</code>) is defined for <code>sum</code> by stating it
after the parameter list. after the parameter list.
<p> <p>
To call the function, we slice the array. This intricate call (we'll show To call the function, we slice the array. This intricate call (we'll show
...@@ -373,7 +373,7 @@ There are also maps, which you can initialize like this: ...@@ -373,7 +373,7 @@ There are also maps, which you can initialize like this:
m := map[string]int{"one":1 , "two":2} m := map[string]int{"one":1 , "two":2}
</pre> </pre>
<p> <p>
The built-in function <code>len()</code>, which returns number of elements, The built-in function <code>len</code>, which returns number of elements,
makes its first appearance in <code>sum</code>. It works on strings, arrays, makes its first appearance in <code>sum</code>. It works on strings, arrays,
slices, maps, and channels. slices, maps, and channels.
<p> <p>
...@@ -401,7 +401,7 @@ for more examples of its use. ...@@ -401,7 +401,7 @@ for more examples of its use.
Most types in Go are values. If you have an <code>int</code> or a <code>struct</code> Most types in Go are values. If you have an <code>int</code> or a <code>struct</code>
or an array, assignment or an array, assignment
copies the contents of the object. copies the contents of the object.
To allocate a new variable, use <code>new()</code>, which To allocate a new variable, use the built-in function <code>new</code>, which
returns a pointer to the allocated storage. returns a pointer to the allocated storage.
<p> <p>
<pre> <pre>
...@@ -418,7 +418,7 @@ or the more idiomatic ...@@ -418,7 +418,7 @@ or the more idiomatic
Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics. Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics.
If you're holding a slice or a map and you modify its contents, other variables If you're holding a slice or a map and you modify its contents, other variables
referencing the same underlying data will see the modification. For these three referencing the same underlying data will see the modification. For these three
types you want to use the built-in function <code>make()</code>: types you want to use the built-in function <code>make</code>:
<p> <p>
<pre> <pre>
m := make(map[string]int) m := make(map[string]int)
...@@ -432,11 +432,11 @@ If you just declare the map, as in ...@@ -432,11 +432,11 @@ If you just declare the map, as in
</pre> </pre>
<p> <p>
it creates a <code>nil</code> reference that cannot hold anything. To use the map, it creates a <code>nil</code> reference that cannot hold anything. To use the map,
you must first initialize the reference using <code>make()</code> or by assignment from an you must first initialize the reference using <code>make</code> or by assignment from an
existing map. existing map.
<p> <p>
Note that <code>new(T)</code> returns type <code>*T</code> while <code>make(T)</code> returns type Note that <code>new(T)</code> returns type <code>*T</code> while <code>make(T)</code> returns type
<code>T</code>. If you (mistakenly) allocate a reference object with <code>new()</code>, <code>T</code>. If you (mistakenly) allocate a reference object with <code>new</code> rather than <code>make</code>,
you receive a pointer to a nil reference, equivalent to you receive a pointer to a nil reference, equivalent to
declaring an uninitialized variable and taking its address. declaring an uninitialized variable and taking its address.
<p> <p>
...@@ -767,7 +767,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u ...@@ -767,7 +767,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
By now this should be easy to follow, but the <code>switch</code> statement introduces some By now this should be easy to follow, but the <code>switch</code> statement introduces some
new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an new features. Like a <code>for</code> loop, an <code>if</code> or <code>switch</code> can include an
initialization statement. The <code>switch</code> on line 18 uses one to create variables initialization statement. The <code>switch</code> on line 18 uses one to create variables
<code>nr</code> and <code>er</code> to hold the return values from <code>f.Read()</code>. (The <code>if</code> on line 25 <code>nr</code> and <code>er</code> to hold the return values from the call to <code>f.Read</code>. (The <code>if</code> on line 25
has the same idea.) The <code>switch</code> statement is general: it evaluates the cases has the same idea.) The <code>switch</code> statement is general: it evaluates the cases
from top to bottom looking for the first case that matches the value; the from top to bottom looking for the first case that matches the value; the
case expressions don't need to be constants or even integers, as long as case expressions don't need to be constants or even integers, as long as
...@@ -779,14 +779,14 @@ in a <code>for</code> statement, a missing value means <code>true</code>. In fa ...@@ -779,14 +779,14 @@ in a <code>for</code> statement, a missing value means <code>true</code>. In fa
is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in is a form of <code>if-else</code> chain. While we're here, it should be mentioned that in
<code>switch</code> statements each <code>case</code> has an implicit <code>break</code>. <code>switch</code> statements each <code>case</code> has an implicit <code>break</code>.
<p> <p>
Line 25 calls <code>Write()</code> by slicing the incoming buffer, which is itself a slice. Line 25 calls <code>Write</code> by slicing the incoming buffer, which is itself a slice.
Slices provide the standard Go way to handle I/O buffers. Slices provide the standard Go way to handle I/O buffers.
<p> <p>
Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input. Now let's make a variant of <code>cat</code> that optionally does <code>rot13</code> on its input.
It's easy to do by just processing the bytes, but instead we will exploit It's easy to do by just processing the bytes, but instead we will exploit
Go's notion of an <i>interface</i>. Go's notion of an <i>interface</i>.
<p> <p>
The <code>cat()</code> subroutine uses only two methods of <code>f</code>: <code>Read()</code> and <code>String()</code>, The <code>cat</code> subroutine uses only two methods of <code>f</code>: <code>Read</code> and <code>String</code>,
so let's start by defining an interface that has exactly those two methods. so let's start by defining an interface that has exactly those two methods.
Here is code from <code>progs/cat_rot13.go</code>: Here is code from <code>progs/cat_rot13.go</code>:
<p> <p>
...@@ -838,7 +838,7 @@ To use the new feature, we define a flag: ...@@ -838,7 +838,7 @@ To use the new feature, we define a flag:
14 var rot13Flag = flag.Bool(&quot;rot13&quot;, false, &quot;rot13 the input&quot;) 14 var rot13Flag = flag.Bool(&quot;rot13&quot;, false, &quot;rot13 the input&quot;)
</pre> </pre>
<p> <p>
and use it from within a mostly unchanged <code>cat()</code> function: and use it from within a mostly unchanged <code>cat</code> function:
<p> <p>
<pre> <!-- progs/cat_rot13.go /func.cat/ /^}/ --> <pre> <!-- progs/cat_rot13.go /func.cat/ /^}/ -->
52 func cat(r reader) { 52 func cat(r reader) {
...@@ -866,7 +866,7 @@ and use it from within a mostly unchanged <code>cat()</code> function: ...@@ -866,7 +866,7 @@ and use it from within a mostly unchanged <code>cat()</code> function:
74 } 74 }
</pre> </pre>
<p> <p>
(We could also do the wrapping in <code>main</code> and leave <code>cat()</code> mostly alone, except (We could also do the wrapping in <code>main</code> and leave <code>cat</code> mostly alone, except
for changing the type of the argument; consider that an exercise.) for changing the type of the argument; consider that an exercise.)
Lines 56 through 58 set it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code> Lines 56 through 58 set it all up: If the <code>rot13</code> flag is true, wrap the <code>reader</code>
we received into a <code>rotate13</code> and proceed. Note that the interface variables we received into a <code>rotate13</code> and proceed. Note that the interface variables
...@@ -1055,7 +1055,7 @@ to that of the <code>Printf</code> call above. ...@@ -1055,7 +1055,7 @@ to that of the <code>Printf</code> call above.
</pre> </pre>
<p> <p>
If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format, If you have your own type you'd like <code>Printf</code> or <code>Print</code> to format,
just give it a <code>String()</code> method that returns a string. The print just give it a <code>String</code> method that returns a string. The print
routines will examine the value to inquire whether it implements routines will examine the value to inquire whether it implements
the method and if so, use it rather than some other formatting. the method and if so, use it rather than some other formatting.
Here's a simple example. Here's a simple example.
...@@ -1076,14 +1076,14 @@ Here's a simple example. ...@@ -1076,14 +1076,14 @@ Here's a simple example.
21 } 21 }
</pre> </pre>
<p> <p>
Since <code>*testType</code> has a <code>String()</code> method, the Since <code>*testType</code> has a <code>String</code> method, the
default formatter for that type will use it and produce the output default formatter for that type will use it and produce the output
<p> <p>
<pre> <pre>
77 Sunset Strip 77 Sunset Strip
</pre> </pre>
<p> <p>
Observe that the <code>String()</code> method calls <code>Sprint</code> (the obvious Go Observe that the <code>String</code> method calls <code>Sprint</code> (the obvious Go
variant that returns a string) to do its formatting; special formatters variant that returns a string) to do its formatting; special formatters
can use the <code>fmt</code> library recursively. can use the <code>fmt</code> library recursively.
<p> <p>
...@@ -1096,7 +1096,7 @@ and such, but that's getting a little off the main thread so we'll leave it ...@@ -1096,7 +1096,7 @@ and such, but that's getting a little off the main thread so we'll leave it
as an exploration exercise. as an exploration exercise.
<p> <p>
You might ask, though, how <code>Printf</code> can tell whether a type implements You might ask, though, how <code>Printf</code> can tell whether a type implements
the <code>String()</code> method. Actually what it does is ask if the value can the <code>String</code> method. Actually what it does is ask if the value can
be converted to an interface variable that implements the method. be converted to an interface variable that implements the method.
Schematically, given a value <code>v</code>, it does this: Schematically, given a value <code>v</code>, it does this:
<p> <p>
...@@ -1141,7 +1141,7 @@ interface type defined in the <code>io</code> library: ...@@ -1141,7 +1141,7 @@ interface type defined in the <code>io</code> library:
<p> <p>
(This interface is another conventional name, this time for <code>Write</code>; there are also (This interface is another conventional name, this time for <code>Write</code>; there are also
<code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.) <code>io.Reader</code>, <code>io.ReadWriter</code>, and so on.)
Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write()</code> Thus you can call <code>Fprintf</code> on any type that implements a standard <code>Write</code>
method, not just files but also network channels, buffers, whatever method, not just files but also network channels, buffers, whatever
you want. you want.
<p> <p>
......
...@@ -272,7 +272,7 @@ Using slices one can write this function (from "sum.go"): ...@@ -272,7 +272,7 @@ Using slices one can write this function (from "sum.go"):
--PROG progs/sum.go /sum/ /^}/ --PROG progs/sum.go /sum/ /^}/
Note how the return type ("int") is defined for "sum()" by stating it Note how the return type ("int") is defined for "sum" by stating it
after the parameter list. after the parameter list.
To call the function, we slice the array. This intricate call (we'll show To call the function, we slice the array. This intricate call (we'll show
...@@ -296,7 +296,7 @@ There are also maps, which you can initialize like this: ...@@ -296,7 +296,7 @@ There are also maps, which you can initialize like this:
m := map[string]int{"one":1 , "two":2} m := map[string]int{"one":1 , "two":2}
The built-in function "len()", which returns number of elements, The built-in function "len", which returns number of elements,
makes its first appearance in "sum". It works on strings, arrays, makes its first appearance in "sum". It works on strings, arrays,
slices, maps, and channels. slices, maps, and channels.
...@@ -321,7 +321,7 @@ An Interlude about Allocation ...@@ -321,7 +321,7 @@ An Interlude about Allocation
Most types in Go are values. If you have an "int" or a "struct" Most types in Go are values. If you have an "int" or a "struct"
or an array, assignment or an array, assignment
copies the contents of the object. copies the contents of the object.
To allocate a new variable, use "new()", which To allocate a new variable, use the built-in function "new", which
returns a pointer to the allocated storage. returns a pointer to the allocated storage.
type T struct { a, b int } type T struct { a, b int }
...@@ -334,7 +334,7 @@ or the more idiomatic ...@@ -334,7 +334,7 @@ or the more idiomatic
Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics. Some types&mdash;maps, slices, and channels (see below)&mdash;have reference semantics.
If you're holding a slice or a map and you modify its contents, other variables If you're holding a slice or a map and you modify its contents, other variables
referencing the same underlying data will see the modification. For these three referencing the same underlying data will see the modification. For these three
types you want to use the built-in function "make()": types you want to use the built-in function "make":
m := make(map[string]int) m := make(map[string]int)
...@@ -344,11 +344,11 @@ If you just declare the map, as in ...@@ -344,11 +344,11 @@ If you just declare the map, as in
var m map[string]int var m map[string]int
it creates a "nil" reference that cannot hold anything. To use the map, it creates a "nil" reference that cannot hold anything. To use the map,
you must first initialize the reference using "make()" or by assignment from an you must first initialize the reference using "make" or by assignment from an
existing map. existing map.
Note that "new(T)" returns type "*T" while "make(T)" returns type Note that "new(T)" returns type "*T" while "make(T)" returns type
"T". If you (mistakenly) allocate a reference object with "new()", "T". If you (mistakenly) allocate a reference object with "new" rather than "make",
you receive a pointer to a nil reference, equivalent to you receive a pointer to a nil reference, equivalent to
declaring an uninitialized variable and taking its address. declaring an uninitialized variable and taking its address.
...@@ -526,7 +526,7 @@ Building on the "file" package, here's a simple version of the Unix utility "cat ...@@ -526,7 +526,7 @@ Building on the "file" package, here's a simple version of the Unix utility "cat
By now this should be easy to follow, but the "switch" statement introduces some By now this should be easy to follow, but the "switch" statement introduces some
new features. Like a "for" loop, an "if" or "switch" can include an new features. Like a "for" loop, an "if" or "switch" can include an
initialization statement. The "switch" on line 18 uses one to create variables initialization statement. The "switch" on line 18 uses one to create variables
"nr" and "er" to hold the return values from "f.Read()". (The "if" on line 25 "nr" and "er" to hold the return values from the call to "f.Read". (The "if" on line 25
has the same idea.) The "switch" statement is general: it evaluates the cases has the same idea.) The "switch" statement is general: it evaluates the cases
from top to bottom looking for the first case that matches the value; the from top to bottom looking for the first case that matches the value; the
case expressions don't need to be constants or even integers, as long as case expressions don't need to be constants or even integers, as long as
...@@ -538,14 +538,14 @@ in a "for" statement, a missing value means "true". In fact, such a "switch" ...@@ -538,14 +538,14 @@ in a "for" statement, a missing value means "true". In fact, such a "switch"
is a form of "if-else" chain. While we're here, it should be mentioned that in is a form of "if-else" chain. While we're here, it should be mentioned that in
"switch" statements each "case" has an implicit "break". "switch" statements each "case" has an implicit "break".
Line 25 calls "Write()" by slicing the incoming buffer, which is itself a slice. Line 25 calls "Write" by slicing the incoming buffer, which is itself a slice.
Slices provide the standard Go way to handle I/O buffers. Slices provide the standard Go way to handle I/O buffers.
Now let's make a variant of "cat" that optionally does "rot13" on its input. Now let's make a variant of "cat" that optionally does "rot13" on its input.
It's easy to do by just processing the bytes, but instead we will exploit It's easy to do by just processing the bytes, but instead we will exploit
Go's notion of an <i>interface</i>. Go's notion of an <i>interface</i>.
The "cat()" subroutine uses only two methods of "f": "Read()" and "String()", The "cat" subroutine uses only two methods of "f": "Read" and "String",
so let's start by defining an interface that has exactly those two methods. so let's start by defining an interface that has exactly those two methods.
Here is code from "progs/cat_rot13.go": Here is code from "progs/cat_rot13.go":
...@@ -569,11 +569,11 @@ To use the new feature, we define a flag: ...@@ -569,11 +569,11 @@ To use the new feature, we define a flag:
--PROG progs/cat_rot13.go /rot13Flag/ --PROG progs/cat_rot13.go /rot13Flag/
and use it from within a mostly unchanged "cat()" function: and use it from within a mostly unchanged "cat" function:
--PROG progs/cat_rot13.go /func.cat/ /^}/ --PROG progs/cat_rot13.go /func.cat/ /^}/
(We could also do the wrapping in "main" and leave "cat()" mostly alone, except (We could also do the wrapping in "main" and leave "cat" mostly alone, except
for changing the type of the argument; consider that an exercise.) for changing the type of the argument; consider that an exercise.)
Lines 56 through 58 set it all up: If the "rot13" flag is true, wrap the "reader" Lines 56 through 58 set it all up: If the "rot13" flag is true, wrap the "reader"
we received into a "rotate13" and proceed. Note that the interface variables we received into a "rotate13" and proceed. Note that the interface variables
...@@ -701,19 +701,19 @@ to that of the "Printf" call above. ...@@ -701,19 +701,19 @@ to that of the "Printf" call above.
--PROG progs/print.go 'NR==21' 'NR==22' --PROG progs/print.go 'NR==21' 'NR==22'
If you have your own type you'd like "Printf" or "Print" to format, If you have your own type you'd like "Printf" or "Print" to format,
just give it a "String()" method that returns a string. The print just give it a "String" method that returns a string. The print
routines will examine the value to inquire whether it implements routines will examine the value to inquire whether it implements
the method and if so, use it rather than some other formatting. the method and if so, use it rather than some other formatting.
Here's a simple example. Here's a simple example.
--PROG progs/print_string.go 'NR==9' END --PROG progs/print_string.go 'NR==9' END
Since "*testType" has a "String()" method, the Since "*testType" has a "String" method, the
default formatter for that type will use it and produce the output default formatter for that type will use it and produce the output
77 Sunset Strip 77 Sunset Strip
Observe that the "String()" method calls "Sprint" (the obvious Go Observe that the "String" method calls "Sprint" (the obvious Go
variant that returns a string) to do its formatting; special formatters variant that returns a string) to do its formatting; special formatters
can use the "fmt" library recursively. can use the "fmt" library recursively.
...@@ -726,7 +726,7 @@ and such, but that's getting a little off the main thread so we'll leave it ...@@ -726,7 +726,7 @@ and such, but that's getting a little off the main thread so we'll leave it
as an exploration exercise. as an exploration exercise.
You might ask, though, how "Printf" can tell whether a type implements You might ask, though, how "Printf" can tell whether a type implements
the "String()" method. Actually what it does is ask if the value can the "String" method. Actually what it does is ask if the value can
be converted to an interface variable that implements the method. be converted to an interface variable that implements the method.
Schematically, given a value "v", it does this: Schematically, given a value "v", it does this:
...@@ -765,7 +765,7 @@ interface type defined in the "io" library: ...@@ -765,7 +765,7 @@ interface type defined in the "io" library:
(This interface is another conventional name, this time for "Write"; there are also (This interface is another conventional name, this time for "Write"; there are also
"io.Reader", "io.ReadWriter", and so on.) "io.Reader", "io.ReadWriter", and so on.)
Thus you can call "Fprintf" on any type that implements a standard "Write()" Thus you can call "Fprintf" on any type that implements a standard "Write"
method, not just files but also network channels, buffers, whatever method, not just files but also network channels, buffers, whatever
you want. you want.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment