Skip to content

Files

Latest commit

 

History

History
280 lines (97 loc) · 20.3 KB

the-go-programming-language.md

File metadata and controls

280 lines (97 loc) · 20.3 KB

The Go Programming Language

> Home

5.2 Recursion

In contrast, typical Go implementations use variable-size stacks that start small and grow as needed up to a limit on the order of a gigabyte. This lets us use recursion safely and without worrying about overflow. (link)

5.8 Deferred Function Calls

Because an anonymous function can access its enclosing function’s variables, including named results, a deferred anonymous function can observe the function’s results. (link)

The defer statement can also be used to pair “on entry” and “on exit” actions when debugging a complex function (link)

defer statement is often used with paired operations like open and close, connect and disconnect, or lock and unlock to ensure that resources are released in all cases, no matter how complex the control flow. (link)

7.6 Sorting with sort.Interface

Each element is indirect, a pointer to a Track. Although the code below would work if we stored the Tracks directly, the sort function will swap many pairs of elements, so it will run faster if each element is a pointer, which is a single machine word, instead of an entire Track, which might be eight words or more. (link)

7.3 Interface Satisfaction

a value of type T does not possess all the methods that a *T pointer does, and as a result it might satisfy fewer interfaces. (link)

Go programmers often say that a concrete type “is a” particular interface type, meaning that it satisfies the interface. For example, a *bytes.Buffer is an io.Writer; an *os.File is an io.ReadWriter. (link)

7.1 Interfaces as Contracts

This freedom to substitute one type for another that satisfies the same interface is called substitutability, (link)

5.4 Errors

Errors are thus an important part of a package’s API or an application’s user interface, and failure is just one of several expected behaviors. This is the approach Go takes to error handling. (link)

Indeed, it’s when the most reliable operations fail unexpectedly that we most need to know why. (link)

7.14 Example: Token-Based XML Decoding

The encoding/xml package also provides a lower-level token-based API for decoding XML. In the token-based style, the parser consumes the input and produces a stream of tokens, primarily of four kinds—StartElement, EndElement, CharData, and Comment—each being a concrete type in the encoding/xml package. Each call to (*xml.Decoder).Token returns a token. (link)

5.6 Anonymous Functions

The problem of iteration variable capture is most often encountered when using the go statement (Chapter 8) or with defer (which we will see in a moment) since both may delay the execution of a function value until after the loop has finished. (link)

for _, dir := range tempDirs() { dir := dir // declares inner dir, initialized to outer dir // ... (link)

dir := d // NOTE: necessary! (link)

the argument “f(item)...” causes all the items in the list returned by f to be appended to the worklist. (link)

topoSort example showed a depth-first traversal; for our web crawler, we’ll use breadth-first traversal, at least initially. In Chapter 8, we’ll explore concurrent traversal. (link)

Instead of appending the raw href attribute value to the links slice, this version parses it as a URL relative to the base URL of the document, resp.Request.UR (link)

Here again we see an example where the lifetime of a variable is not determined by its scope (link)

The squares example demonstrates that function values are not just code but can have state. The anonymous inner function can access and update the local variables of the enclosing function squares (link)

More importantly, functions defined in this way have access to the entire lexical environment, so the inner function can refer to variables from the enclosing function (link)

8.6 Example: Concurrent Web Crawler

Also notice that the initial send of the command-line arguments to the worklist must run in its own goroutine to avoid deadlock, a stuck situation in which both the main goroutine and a crawler goroutine attempt to send to each other while neither is receiving. An alternative solution would be to use a buffered channel (link)

we’ll make it concurrent so that independent calls to crawl can exploit the I/O parallelism available in the web. (link)

4.2 Slices

So, if you need to test whether a slice is empty, use len(s) == 0, not s == nil (link)

The zero value of a slice type is nil (link)

, unlike array elements, the elements of a slice are indirect, making it possible for a slice to contain itself (link)

bytes.Equal function for comparing two slices of bytes ([]byte) (link)

Unlike arrays, slices are not comparable, so we cannot use == to test whether two slices contain the same elements. (link)

A slice literal looks like an array literal, a sequence of values separated by commas and surrounded by braces, but the size is not given. (link)

A simple way to rotate a slice left by n elements is to apply the reverse function three times, first to the leading n elements, then to the remaining elements, and finally to the whole slice. (To rotate to the right, make the third call first.) (link)

In other words, copying a slice creates an alias (§2.3.2) for the underlying array. (link)

The slice operator s[i:j], where 0 ≤ i ≤ j ≤ cap(s), creates a new slice that refers to elements i through j-1 of the sequence s, which may be an array variable, a pointer to an array, or another slice (link)

The slice operator s[i:j], where 0 ≤ i ≤ j ≤ cap(s), creates a new slice that refers to elements i through j-1 of the sequence s, which may be an array variable, (link)

Vikram: [s can be a pointer]

5.5 Function Values

Using a function value, we can separate the logic for tree traversal from the logic for the action to be applied to each node, letting us reuse the traversal with different actions. (link)

8.1 Goroutines

The main function then returns. When this happens, all goroutines are abruptly terminated and the program exits. Other than by returning from main or exiting the program, there is no programmatic way for one goroutine to stop another, but as we will see later, there are ways to communicate with a goroutine to request that it stop itself. (link)

In Go, each concurrently executing activity is called a goroutine. (link)

5.3 Multiple Return Values

This is called a bare return (link)

7.5 Interface Values

The problem is that although a nil *bytes.Buffer pointer has the methods needed to satisfy the interface, it doesn’t satisfy the behavioral requirements of the interface. In particular, the call violates the implicit precondition of (*bytes.Buffer).Write that its receiver is not nil, so assigning the nil pointer to the interface was a mistake. The solution is to change the type of buf in main to io.Writer, thereby avoiding the assignment of the dysfunctional value to the interface in the first place: (link)

When main calls f, it assigns a nil pointer of type *bytes.Buffer to the out parameter, so the dynamic value of out is nil. However, its dynamic type is *bytes.Buffer, meaning that out is a non-nil interface containing a nil pointer value (Figure 7.5), so the defensive check out != nil is still true. (link)

When handling errors, or during debugging, it is often helpful to report the dynamic type of an interface value. For that, we use the fmt package’s %T verb: (link)

7.7 The http.Handler Interface

The behavior of its ServeHTTP method is to call the underlying function. HandlerFunc is thus an adapter that lets a function value satisfy an interface, where the function and the interface’s sole method have the same signature. In effect, this trick lets a single type such as database satisfy the http.Handler interface several different ways: once through its list method, once through its price method, and so on. (link)

w.WriteHeader(http.StatusNotFound); this must be done before writing any text to w. (Incidentally, http.ResponseWriter is another interface. It augments io.Writer with methods for sending HTTP response headers.) (link)

3.5 Strings

fmt.Println(strconv.FormatInt(int64(x), 2)) // "1111011" (link)

In addition to conversions between strings, runes, and bytes, it’s often necessary to convert between numeric values and their string representations. This is done with functions from the strconv package. (link)

The bytes package provides the Buffer type for efficient manipulation of byte slices (link)

A string contains an array of bytes that, once created, is immutable. By contrast, the elements of a byte slice can be freely modified. (link)

The path and path/filepath packages provide a more general set of functions for manipulating hierarchical names (link)

The strconv package provides functions for converting boolean, integer, and floating-point values to and from their string representations, and functions for quoting and unquoting strings. (link)

Because strings are immutable, building up strings incrementally can involve a lot of allocation and copying. In such cases, it’s more efficient to use the bytes.Buffer type, which we’ll show in a moment. (link)

The verb % x in the first Printf inserts a space between each pair of hex digits. (link)

A []rune conversion applied to a UTF-8-encoded string returns the sequence of Unicode code points (link)

unexpected input byte, it generates a special Unicode replacement character, 'uFFFD', which is usually printed as a white question mark inside a black (link)

range loop, when applied to a string, performs UTF-8 decoding implicitly. (link)

A rune whose value is less than 256 may be written with a single hexadecimal escape, such as 'x41' for 'A', but for higher values, a u or U escape must be used. Consequently, 'xe4xb8x96' is not a legal rune literal, even though those three bytes are a valid UTF-8 encoding of a single code point. (link)

Vikram: [So until 256 the hexadecimal number is the same for the bytes and the unicode code point (rune). A character has a number in the unicode code point table. This number represented in hex will be 'uhhhh', but when encoded will have a different bytes sequence which will be 'xhhh'. So the number of bytes and the actual values will be different.]

UTF-8 was invented by Ken Thompson and Rob Pike, two of the creators of Go, (link)

UTF-8 is a variable-length encoding of Unicode code points as bytes. (link)

The natural data type to hold a single rune is int32, and that’s what Go uses; it has the synonym rune for precisely this purpose (link)

Unicode code point or, in Go terminology, a rune. (link)

A raw string literal is written ..., using backquotes instead of double quotes. (link)

Immutability means that it is safe for two copies of a string to share the same underlying memory, making it cheap to copy strings of any length. (link)

Since strings are immutable, constructions that try to modify a string’s data in place are not allowed: (link)

8.5 Looping in Parallel

Problems like this that consist entirely of subproblems that are completely independent of each other are described as embarrassingly parallel. (link)

5.1 Function Declarations

Arguments are passed by value, so the function receives a copy of each argument; modifications to the copy do not affect the caller. However, if the argument contains some kind of reference, like a pointer, slice, map, function, or channel, then the caller may be affected by any modifications the function makes to variables indirectly referred to by the argument. (link)

7.2 Interface Types

The syntax used above, which resembles struct embedding, lets us name another interface as a shorthand for writing out all of its methods. This is called embedding an interface (link)

7.10 Type Assertions

A type assertion is an operation applied to an interface value. Syntactically, it looks like x.(T), where x is an expression of an interface type and T is a type, called the “asserted” type. A type assertion checks that the dynamic type of its operand matches the asserted type (link)

7.15 A Few Words of Advice

. Not everything need be an object; standalone functions have their place, as do unencapsulated data types (link)

Interfaces are only needed when there are two or more concrete types that must be dealt with in a uniform way. (link)

8. Goroutines and Channels

This chapter presents goroutines and channels, which support communicating sequential processes or CSP, a model of concurrency in which values are passed between independent activities (goroutines) but variables are for the most part confined to a single activity. (link)

> Home