mirror of
https://github.com/golang/go
synced 2024-11-22 01:24:42 -07:00
initialization
R=rsc DELTA=292 (124 added, 165 deleted, 3 changed) OCL=35936 CL=35939
This commit is contained in:
parent
69fc06dfa1
commit
6f89f3f08d
@ -125,7 +125,7 @@ x<<8 + y<<16
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h2>Commentary</h2>
|
||||
<h2 id="commentary">Commentary</h2>
|
||||
|
||||
<p>
|
||||
Go provides C-style <code>/* */</code> block comments
|
||||
@ -1304,7 +1304,129 @@ There's even more to printing than we've covered here. See the <code>godoc</cod
|
||||
for package <code>fmt</code> for the details.
|
||||
</p>
|
||||
|
||||
<h2>Methods</h2>
|
||||
<h2 id="initialization">Initialization</h2>
|
||||
|
||||
<p>
|
||||
Although it doesn't look superficially very different from
|
||||
initialization in C or C++, initialization in Go is more powerful.
|
||||
Complex structures can be built during initialization and the ordering
|
||||
issues between initialized objects in different packages are handled
|
||||
correctly.
|
||||
</p>
|
||||
|
||||
<h3 id="constants">Constants</h3>
|
||||
|
||||
<p>
|
||||
Constants in Go are just that—constant.
|
||||
They are created at compile time, even when defined as
|
||||
locals in functions,
|
||||
and can only be numbers, strings or booleans.
|
||||
Because of the compile-time restriction, the expressions
|
||||
that define them must be constant expressions,
|
||||
evaluatable by the compiler. For instance,
|
||||
<code>1<<3</code> is a constant expression, while
|
||||
<code>math.Sin(math.Pi/4)</code> is not because
|
||||
the function call to <code>math.Sin</code> needs
|
||||
to happen at run time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In Go, enumerated constants are created using the <code>iota</code>
|
||||
enumerator. Since <code>iota</code> can be part of an expression and
|
||||
expressions can be implicitly repeated, it is easy to build intricate
|
||||
sets of values.
|
||||
<p>
|
||||
<pre>
|
||||
type ByteSize float64
|
||||
const (
|
||||
_ = iota; // ignore first value by assigning to blank identifier
|
||||
KB ByteSize = 1<<(10*iota);
|
||||
MB;
|
||||
GB;
|
||||
TB;
|
||||
PB;
|
||||
YB;
|
||||
)
|
||||
</pre>
|
||||
<p>
|
||||
The ability to attach a method such as <code>String</code> to a
|
||||
type makes it possible for such values to format themselves
|
||||
automatically for printing, even as part of a general type.
|
||||
</p>
|
||||
<pre>
|
||||
func (b ByteSize) String() string {
|
||||
switch {
|
||||
case s >= YB:
|
||||
return fmt.Sprintf("%.2fYB", b/YB)
|
||||
case s >= PB:
|
||||
return fmt.Sprintf("%.2fPB", b/PB)
|
||||
case s >= TB:
|
||||
return fmt.Sprintf("%.2fTB", b/TB)
|
||||
case s >= GB:
|
||||
return fmt.Sprintf("%.2fGB", b/GB)
|
||||
case s >= MB:
|
||||
return fmt.Sprintf("%.2fMB", b/MB)
|
||||
case s >= KB:
|
||||
return fmt.Sprintf("%.2fKB", b/KB)
|
||||
}
|
||||
return fmt.Sprintf("%.2fB", b);
|
||||
}
|
||||
</pre>
|
||||
<p>
|
||||
The expression <code>YB</code> prints as <code>1.00YB</code>,
|
||||
while <code>ByteSize(1e13)</code> prints as <code>9.09TB</code>,
|
||||
</p>
|
||||
|
||||
<h3 id="variables">Variables</h3>
|
||||
|
||||
<p>
|
||||
Variables can be initialized just like constants but the
|
||||
initializer can be a general expression computed at run time.
|
||||
</p>
|
||||
<pre>
|
||||
var (
|
||||
HOME = os.Getenv("HOME");
|
||||
USER = os.Getenv("USER");
|
||||
GOROOT = os.Getenv("GOROOT");
|
||||
)
|
||||
</pre>
|
||||
|
||||
<h3 id="init">The init function</h3>
|
||||
|
||||
<p>
|
||||
Finally, each source file can define its own <code>init()</code> function to
|
||||
set up whatever state is required. The only restriction is that, although
|
||||
goroutines can be launched during initialization, they will not begin
|
||||
execution until it completes; initialization always runs as a single thread
|
||||
of execution.
|
||||
And finally means finally: <code>init()</code> is called after all the
|
||||
variable declarations in the package have evaluated their initializers,
|
||||
and those are evaluated only after all the imported packages have been
|
||||
initialized.
|
||||
</p>
|
||||
<p>
|
||||
Besides initializations that cannot be expressed as declarations,
|
||||
a common use of <code>init()</code> functions is to verify or repair
|
||||
correctness of the program state before real execution begins.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func init() {
|
||||
if USER == "" {
|
||||
log.Exit("$USER not set")
|
||||
}
|
||||
if HOME == "" {
|
||||
HOME = "/usr/" + USER
|
||||
}
|
||||
if GOROOT == "" {
|
||||
GOROOT = HOME + "/go"
|
||||
}
|
||||
// GOROOT may be overridden by --goroot flag on command line.
|
||||
flag.StringVar(&GOROOT, "goroot", GOROOT, "Go root directory");
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="methods">Methods</h2>
|
||||
|
||||
<h3 id="pointers_vs_values">Pointers vs. Values</h3>
|
||||
<p>
|
||||
@ -2000,178 +2122,15 @@ for try := 0; try < 2; try++ {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>More to come</h2>
|
||||
|
||||
<!---
|
||||
|
||||
<h2 id="idioms">Idioms</h2>
|
||||
|
||||
|
||||
<h3 id="buffer-slice">Use parallel assignment to slice a buffer</h3>
|
||||
|
||||
<pre>
|
||||
header, body, checksum := buf[0:20], buf[20:n-4], buf[n-4:n];
|
||||
</pre>
|
||||
|
||||
<h2>Data-Driven Programming</h2>
|
||||
|
||||
<p>
|
||||
tables
|
||||
</p>
|
||||
|
||||
<p>
|
||||
XXX struct tags for marshaling.
|
||||
template
|
||||
eventually datafmt
|
||||
</p>
|
||||
|
||||
<h2>Testing</h2>
|
||||
|
||||
<h3 id="no-abort">Run tests to completion</h3>
|
||||
|
||||
<p>
|
||||
Tests should not stop early just because one case has misbehaved.
|
||||
If at all possible, let tests continue, in order to characterize the
|
||||
problem in more detail.
|
||||
For example, it is more useful for a test to report that <code>isPrime</code>
|
||||
gives the wrong answer for 4, 8, 16 and 32 than to report
|
||||
that <code>isPrime</code> gives the wrong answer for 4 and therefore
|
||||
no more tests were run.
|
||||
XXX
|
||||
test bottom up
|
||||
test runs top to bottom
|
||||
how to use gotest
|
||||
XXX
|
||||
</p>
|
||||
|
||||
<h3 id="good-errors">Print useful errors when tests fail</h3>
|
||||
|
||||
<p>
|
||||
If a test fails, print a concise message explaining the context,
|
||||
what happened, and what was expected.
|
||||
Many testing environments encourage causing the
|
||||
program to crash, but stack traces and core dumps
|
||||
have low signal to noise ratios and require reconstructing
|
||||
the situation from scratch.
|
||||
The programmer who triggers the test failure may be someone
|
||||
editing the code months later or even someone editing a different
|
||||
package on which the code depends.
|
||||
Time invested writing a good error message now pays off when
|
||||
the test breaks later.
|
||||
</p>
|
||||
|
||||
<h3 id="data-driven-tests">Use data-driven tests</h3>
|
||||
|
||||
<p>
|
||||
Many tests reduce to running the same code multiple times,
|
||||
with different input and expected output.
|
||||
Instead of using cut and paste to write this code,
|
||||
create a table of test cases and write a single test that
|
||||
iterates over the table.
|
||||
Once the table is written, you might find that it
|
||||
serves well as input to multiple tests. For example,
|
||||
a single table of encoded/decoded pairs can be
|
||||
used by both <code>TestEncoder</code> and <code>TestDecoder</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This data-driven style dominates in the Go package tests.
|
||||
<font color="red">((link to go code search for 'for.*range' here))</font>
|
||||
</p>
|
||||
|
||||
<h3 id="reflect.DeepEqual">Use reflect.DeepEqual to compare complex values</h3>
|
||||
|
||||
<p>
|
||||
The <code>reflect.DeepEqual</code> function tests
|
||||
whether two complex data structures have equal values.
|
||||
If a function returns a complex data structure,
|
||||
<code>reflect.DeepEqual</code> combined with table-driven testing
|
||||
makes it easy to check that the return value is
|
||||
exactly as expected.
|
||||
</p>
|
||||
|
||||
<h2 id="be-consistent">Be consistent</h2>
|
||||
|
||||
<p>
|
||||
Programmers often want their style to be distinctive,
|
||||
writing loops backwards or using custom spacing and
|
||||
naming conventions. Such idiosyncrasies come at a
|
||||
price, however: by making the code look different,
|
||||
they make it harder to understand.
|
||||
Consistency trumps personal
|
||||
expression in programming.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a program does the same thing twice,
|
||||
it should do it the same way both times.
|
||||
Conversely, if two different sections of a
|
||||
program look different, the reader will
|
||||
expect them to do different things.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Consider <code>for</code> loops.
|
||||
Traditionally, a loop over <code>n</code>
|
||||
elements begins:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for i := 0; i < n; i++ {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Much of the time, the loop could run in the opposite order
|
||||
and still be correct:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
for i := n-1; i >= 0; i-- {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The convention
|
||||
is to count up unless to do so would be incorrect.
|
||||
A loop that counts down implicitly says “something
|
||||
special is happening here.”
|
||||
A reader who finds a program in which some
|
||||
loops count up and the rest count down
|
||||
will spend time trying to understand why.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Loop direction is just one
|
||||
programming decision that must be made
|
||||
consistently; others include
|
||||
formatting, naming variables and methods,
|
||||
whether a type
|
||||
has a constructor, what tests look like, and so on.
|
||||
Why is this variable called <code>n</code> here and <code>cnt</code> there?
|
||||
Why is the <code>Log</code> constructor <code>CreateLog</code> when
|
||||
the <code>List</code> constructor is <code>NewList</code>?
|
||||
Why is this data structure initialized using
|
||||
a structure literal when that one
|
||||
is initialized using individual assignments?
|
||||
These questions distract from the important one:
|
||||
what does the code do?
|
||||
Moreover, internal consistency is important not only within a single file,
|
||||
but also within the surrounding source files.
|
||||
When editing code, read the surrounding context
|
||||
and try to mimic it as much as possible, even if it
|
||||
disagrees with the rules here.
|
||||
It should not be possible to tell which lines
|
||||
you wrote or edited based on style alone.
|
||||
Consistency about little things
|
||||
lets readers concentrate on big ones.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<!--
|
||||
TODO
|
||||
verifying implementation
|
||||
type Color uint32
|
||||
|
||||
// Check that Color implements image.Color and image.Image
|
||||
var _ image.Color = Black
|
||||
var _ image.Image = Black
|
||||
</pre>
|
||||
<pre>
|
||||
verifying implementation
|
||||
type Color uint32
|
||||
|
||||
// Check that Color implements image.Color and image.Image
|
||||
var _ image.Color = Black
|
||||
var _ image.Image = Black
|
||||
</pre>
|
||||
-->
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user