The Go Programming Language
Rate it:
Open Preview
Read between October 26 - December 7, 2021
32%
Flag icon
Any number of calls may be deferred; they are executed in the reverse of the order in which they were deferred.
33%
Flag icon
Deferred functions run after return statements have updated the function’s result variables.
33%
Flag icon
By naming its result variable and adding a defer statement, we can make the function print its arguments and results each time it is called.
33%
Flag icon
deferred anonymous function can even change the values that the enclosing function returns to its caller:
Osvaldo Santana Neto
Ugh! Qui mêda!
33%
Flag icon
Because deferred functions aren’t executed until the very end of a function’s execution, a defer statement in a loop deserves extra scrutiny. The code below could run out of file descriptors since no file will be closed until all files have been processed:
33%
Flag icon
One solution is to move the loop body, including the defer statement, into another function that is called on each iteration.
33%
Flag icon
It’s tempting to use a second deferred call, to f.Close, to close the local file, but this would be subtly wrong because os.Create opens a file for writing, creating it as needed. On many file systems, notably NFS, write errors are not reported immediately but may be postponed until the file is closed. Failure to check the result of the close operation could cause serious data loss to go unnoticed.
33%
Flag icon
The Must prefix is a common naming convention for functions of this kind, like template.Must
33%
Flag icon
As we will see soon, it is possible for a function to recover from a panic so that it does not terminate the program.
34%
Flag icon
Furthermore, by replacing a crash with, say, a line in a log file, indiscriminate recovery may cause bugs to go unnoticed.
35%
Flag icon
If the receiver p is a variable of type Point but the method requires a *Point receiver, we can use this shorthand: p.ScaleBy(2) and the compiler will perform an implicit &p on the variable.
35%
Flag icon
The compiler inserts an implicit * operation for us. These two function calls are equivalent: pptr.Distance(q) (*pptr).Distance(q)
36%
Flag icon
A method expression, written T.f or (*T).f where T is a type, yields a function value with a regular first parameter taking the place of the receiver, so it can be called in the usual way.
37%
Flag icon
variable or method of an object is said to be encapsulated if it is inaccessible to clients of the object. Encapsulation, sometimes called information hiding, is a key aspect of object-oriented programming.
38%
Flag icon
Many object-oriented languages have some notion of interfaces, but what makes Go’s interfaces so distinctive is that they are satisfied implicitly.
38%
Flag icon
This freedom to substitute one type for another that satisfies the same interface is called substitutability,
38%
Flag icon
The order in which the methods appear is immaterial. All that matters is the set of methods.
39%
Flag icon
Only the methods revealed by the interface type may be called, even if the concrete type has others:
39%
Flag icon
So what does the type interface{}, which has no methods at all, tell us about the concrete types that satisfy it? That’s right: nothing. This may seem useless, but in fact the type interface{}, which is called the empty interface type, is indispensable. Because the empty interface type places no demands on the types that satisfy it, we can assign any value to the empty interface.
48%
Flag icon
A good rule of thumb for interface design is ask only for what you need.
49%
Flag icon
When a value is sent on an unbuffered channel, the receipt of the value happens before the reawakening of the sending goroutine.
50%
Flag icon
There is no way to test directly whether a channel has been closed, but there is a variant of the receive operation that produces two results: the received channel element, plus a boolean value, conventionally called ok, which is true for a successful receive and false for a receive on a closed and drained channel.
50%
Flag icon
Because the syntax above is clumsy and this pattern is common, the language lets us use a range loop to iterate over channels too.
50%
Flag icon
The type chan<- int, a send-only channel of int, allows sends but not receives. Conversely, the type <-chan int, a receive-only channel of int, allows receives but not sends.
50%
Flag icon
Since the close operation asserts that no more sends will occur on a channel, only the sending goroutine is in a position to call it,
50%
Flag icon
Conversions from bidirectional to unidirectional channel types are permitted in any assignment.
51%
Flag icon
the unlikely event that a program needs to know the channel’s buffer capacity, it can be obtained by calling the built-in cap function:
51%
Flag icon
When applied to a channel, the built-in len function returns the number of elements currently buffered.
51%
Flag icon
Channels are deeply connected to goroutine scheduling, and without another goroutine receiving from the channel, a sender—and perhaps the whole program—risks becoming blocked forever. If all you need is a simple queue, make one using a slice.
51%
Flag icon
Had we used an unbuffered channel, the two slower goroutines would have gotten stuck trying to send their responses on a channel from which no goroutine will ever receive. This situation, called a goroutine leak, would be a bug. Unlike garbage variables, leaked goroutines are not automatically collected, so it is important to make sure that goroutines terminate themselves when no longer needed.
55%
Flag icon
When we cannot confidently say that one event happens before the other, then the events x and y are concurrent.
56%
Flag icon
This is what is meant by the Go mantra “Do not communicate by sharing memory; instead, share memory by communicating.”
58%
Flag icon
(We hope that by now you are developing a new intuition about concurrency, that intuitions about concurrency are not to be trusted!)
64%
Flag icon
Maurice Wilkes, the developer of EDSAC, the first stored-program computer, had a startling insight while climbing the stairs of his laboratory in 1949. In Memoirs of a Computer Pioneer, he recalled, “The realization came over me with full force that a good part of the remainder of my life was going to be spent in finding errors in my own programs.” Surely every programmer of a stored-program computer since then can sympathize with Wilkes, though perhaps not without some bemusement at his naïveté about the difficulties of software construction.
64%
Flag icon
func TestName(t *testing.T) {     // ... }
67%
Flag icon
An application that often fails when it encounters new but valid inputs is called buggy; a test that spuriously fails when a sound change was made to the program is called brittle.
67%
Flag icon
The most brittle tests, which fail for almost any change to the production code, good or bad, are sometimes called change detector or status quo tests, and the time spent dealing with them can quickly deplete any benefit they once seemed to provide.
67%
Flag icon
“Testing shows the presence, not the absence of bugs.”
68%
Flag icon
Achieving 100% statement coverage sounds like a noble goal, but it is not usually feasible in practice, nor is it likely to be a good use of effort. Just because a statement is executed does not mean it is bug-free; statements containing complex expressions must be executed many times with different inputs to cover the interesting cases. Some statements, like the panic statements above, can never be reached. Others, such as those that handle esoteric errors, are hard to exercise but rarely reached in practice. Testing is fundamentally a pragmatic endeavor, a trade-off between the cost of ...more
« Prev 1 2 Next »