_content/blog: mark Go code blocks as Go
Label every Go code block in the blog with the "go" language,
in preparation for client-side coloring of Go comments and
string literals, which will key on these labels:
- Indented code blocks containing Go are converted to fenced
```go blocks (or ~~~go within {{raw `...`}} template strings,
where a backquote would end the string).
- Fences labeled "Go" are changed to "go", for consistency and
so that a case-sensitive class selector (language-go) matches.
- Raw <pre> elements containing Go (in gofix.md and inliner.md)
get lang=go.
Blocks were classified using go/scanner-based heuristics
(snippets are often fragments, so go/parser was unsuitable),
then reviewed by hand. Shell sessions, tool output, C code,
protobuf, JSON, and the math notation of type-inference.md
are left unlabeled.
turkey-doodle.md's <pre> is deliberately left unlabeled,
since it contains hyperlinks that a token colorizer that
replaces the element's content would discard.
The rendered HTML of every affected post is unchanged apart
from the added class/lang attributes.
Change-Id: I3696d88c55ba80205417dcfbff554d2153486612
Reviewed-on: https://go-review.googlesource.com/c/website/+/842285
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/_content/blog/alias-names.md b/_content/blog/alias-names.md
index c6e6902..c84318b 100644
--- a/_content/blog/alias-names.md
+++ b/_content/blog/alias-names.md
@@ -87,14 +87,14 @@
In contrast to a regular [type definition](/ref/spec#Type_definitions)
-```
+```go
type T T0
```
which declares a _new type_ that is never identical to the type on the right-hand side
of the declaration, an [alias declaration](/ref/spec#Alias_declarations)
-```
+```go
type A = T // the "=" indicates an alias declaration
```
declares only a _new name_ `A` for the type on the right-hand side:
@@ -103,7 +103,7 @@
Alias declarations make it possible to provide a new name (in a new package!)
for a given type while retaining type identity:
-```
+```go
package pkg2
import "path/to/pkg1"
@@ -136,13 +136,13 @@
with an optional type parameter list following the identifier (the alias name) on the left-hand side.
Before this change one could only write:
-```
+```go
type Alias = someType
```
but now we can also declare type parameters with the alias declaration:
-```
+```go
type Alias[P1 C1, P2 C2] = someType
```
@@ -150,7 +150,7 @@
The original package `pkg1` declared and exported a generic type `G` with a type parameter `P`
that is suitably constrained:
-```
+```go
package pkg1
type Constraint someConstraint
@@ -160,7 +160,7 @@
If the need arises to provide access to the same type `G` from a new package `pkg2`,
a generic alias type is just the ticket [(playground)](/play/p/wKOf6NbVtdw?v=gotip):
-```
+```go
package pkg2
import "path/to/pkg1"
@@ -171,7 +171,7 @@
Note that one **cannot** simply write
-```
+```go
type G = pkg1.G
```
@@ -199,13 +199,13 @@
match the number of type parameters of the aliased type.
Consider a generic map type:
-```
+```go
type Map[K comparable, V any] mapImplementation
```
If uses of `Map` as sets are common, the alias
-```
+```go
type Set[K comparable] = Map[K, bool]
```
@@ -221,7 +221,7 @@
For instance, reusing the set example above, one could define
an `IntSet` as follows:
-```
+```go
type integers interface{ ~int | ~int8 | ~int16 | ~int32 | ~int64 }
type IntSet[K integers] = Set[K]
```
@@ -236,7 +236,7 @@
make it possible to create generic type literals
[(playground)](/play/p/wql3NJaUs0o?v=gotip):
-```
+```go
type Point3D[E any] = struct{ x, y, z E }
```
@@ -250,7 +250,7 @@
Before the introduction of alias types, Go had only one form of type declarations:
-```
+```go
type TypeName existingType
```
@@ -263,7 +263,7 @@
With the introduction of alias types in Go 1.9 it became possible to give
a name (an alias) to type literals, too. For instance, consider:
-```
+```go
type Point2D = struct{ x, y int }
```
diff --git a/_content/blog/allocation-optimizations.md b/_content/blog/allocation-optimizations.md
index 130d330..e8bfd82 100644
--- a/_content/blog/allocation-optimizations.md
+++ b/_content/blog/allocation-optimizations.md
@@ -27,13 +27,15 @@
Consider the task of building a slice of tasks to process:
{{raw `
- func process(c chan task) {
- var tasks []task
- for t := range c {
- tasks = append(tasks, t)
- }
- processAll(tasks)
+~~~go
+func process(c chan task) {
+ var tasks []task
+ for t := range c {
+ tasks = append(tasks, t)
}
+ processAll(tasks)
+}
+~~~
`}}
Let's walk through what happens at runtime when pulling tasks from the
@@ -75,13 +77,15 @@
allocations.
{{raw `
- func process2(c chan task) {
- tasks := make([]task, 0, 10) // probably at most 10 tasks
- for t := range c {
- tasks = append(tasks, t)
- }
- processAll(tasks)
+~~~go
+func process2(c chan task) {
+ tasks := make([]task, 0, 10) // probably at most 10 tasks
+ for t := range c {
+ tasks = append(tasks, t)
}
+ processAll(tasks)
+}
+~~~
`}}
This is a reasonable optimization to do. It is never incorrect; your
@@ -111,13 +115,15 @@
Maybe we can pass in an estimated length?
{{raw `
- func process3(c chan task, lengthGuess int) {
- tasks := make([]task, 0, lengthGuess)
- for t := range c {
- tasks = append(tasks, t)
- }
- processAll(tasks)
+~~~go
+func process3(c chan task, lengthGuess int) {
+ tasks := make([]task, 0, lengthGuess)
+ for t := range c {
+ tasks = append(tasks, t)
}
+ processAll(tasks)
+}
+~~~
`}}
This lets the caller pick a good size for the `tasks` slice, which may
@@ -135,18 +141,20 @@
only in cases where the guess is small:
{{raw `
- func process4(c chan task, lengthGuess int) {
- var tasks []task
- if lengthGuess <= 10 {
- tasks = make([]task, 0, 10)
- } else {
- tasks = make([]task, 0, lengthGuess)
- }
- for t := range c {
- tasks = append(tasks, t)
- }
- processAll(tasks)
+~~~go
+func process4(c chan task, lengthGuess int) {
+ var tasks []task
+ if lengthGuess <= 10 {
+ tasks = make([]task, 0, 10)
+ } else {
+ tasks = make([]task, 0, lengthGuess)
}
+ for t := range c {
+ tasks = append(tasks, t)
+ }
+ processAll(tasks)
+}
+~~~
`}}
Kind of ugly, but it would work. When the guess is small, you use a
@@ -179,13 +187,15 @@
Upgrade to Go 1.26!
{{raw `
- func process(c chan task) {
- var tasks []task
- for t := range c {
- tasks = append(tasks, t)
- }
- processAll(tasks)
+~~~go
+func process(c chan task) {
+ var tasks []task
+ for t := range c {
+ tasks = append(tasks, t)
}
+ processAll(tasks)
+}
+~~~
`}}
In Go 1.26, we allocate the same kind of small, speculative backing
@@ -217,13 +227,15 @@
disappears when `extract` returns.
{{raw `
- func extract(c chan task) []task {
- var tasks []task
- for t := range c {
- tasks = append(tasks, t)
- }
- return tasks
+~~~go
+func extract(c chan task) []task {
+ var tasks []task
+ for t := range c {
+ tasks = append(tasks, t)
}
+ return tasks
+}
+~~~
`}}
But you might think, the *returned* slice can't be allocated on the
@@ -231,15 +243,17 @@
garbage? Maybe we can allocate those on the stack?
{{raw `
- func extract2(c chan task) []task {
- var tasks []task
- for t := range c {
- tasks = append(tasks, t)
- }
- tasks2 := make([]task, len(tasks))
- copy(tasks2, tasks)
- return tasks2
+~~~go
+func extract2(c chan task) []task {
+ var tasks []task
+ for t := range c {
+ tasks = append(tasks, t)
}
+ tasks2 := make([]task, len(tasks))
+ copy(tasks2, tasks)
+ return tasks2
+}
+~~~
`}}
Then the `tasks` slice never escapes `extract2`. It can benefit from
@@ -257,14 +271,16 @@
code to something like this:
{{raw `
- func extract3(c chan task) []task {
- var tasks []task
- for t := range c {
- tasks = append(tasks, t)
- }
- tasks = runtime.move2heap(tasks)
- return tasks
+~~~go
+func extract3(c chan task) []task {
+ var tasks []task
+ for t := range c {
+ tasks = append(tasks, t)
}
+ tasks = runtime.move2heap(tasks)
+ return tasks
+}
+~~~
`}}
`runtime.move2heap` is a special compiler+runtime function that is the
diff --git a/_content/blog/appengine-gopath.md b/_content/blog/appengine-gopath.md
index a65c0b1..2a8e063 100644
--- a/_content/blog/appengine-gopath.md
+++ b/_content/blog/appengine-gopath.md
@@ -45,7 +45,9 @@
When writing your App Engine app, import the oauth package just as you would in a regular Go program:
- import "golang.org/x/oauth2"
+```go
+import "golang.org/x/oauth2"
+```
Now, whether running your app with the dev\_appserver or deploying it with appcfg,
the tools will find the oauth package in your workspace. It just works.
@@ -71,15 +73,21 @@
which specifies a build constraint to ensure that it is not built on Windows
systems (which do not have symbolic links):
- // +build !windows
+```go
+// +build !windows
+```
The App Engine SDK introduces a new build constraint term: "appengine". Files that specify
- // +build appengine
+```go
+// +build appengine
+```
will be built by the App Engine SDK and ignored by the go tool. Conversely, files that specify
- // +build !appengine
+```go
+// +build !appengine
+```
are ignored by the App Engine SDK, while the go tool will happily build them.
@@ -93,21 +101,23 @@
Let's take a simple Go web server and turn it into a hybrid app. This is main.go:
- package main
+```go
+package main
- import (
- "fmt"
- "net/http"
- )
+import (
+ "fmt"
+ "net/http"
+)
- func main() {
- http.HandleFunc("/", handler)
- http.ListenAndServe("localhost:8080", nil)
- }
+func main() {
+ http.HandleFunc("/", handler)
+ http.ListenAndServe("localhost:8080", nil)
+}
- func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprint(w, "Hello!")
- }
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, "Hello!")
+}
+```
Build this with the go tool and you'll get a stand-alone web server executable.
@@ -116,20 +126,22 @@
To convert main.go to an App Engine app, drop the call to ListenAndServe
and register the handler in an init function (which runs before main). This is app.go:
- package main
+```go
+package main
- import (
- "fmt"
- "net/http"
- )
+import (
+ "fmt"
+ "net/http"
+)
- func init() {
- http.HandleFunc("/", handler)
- }
+func init() {
+ http.HandleFunc("/", handler)
+}
- func handler(w http.ResponseWriter, r *http.Request) {
- fmt.Fprint(w, "Hello!")
- }
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, "Hello!")
+}
+```
To make this a hybrid app, we need to split it into an App Engine-specific part,
an stand-alone binary-specific part, and the parts common to both versions.
@@ -143,15 +155,17 @@
main.go runs the web server. It includes the "!appengine" build constraint,
as it must only be included when building the stand-alone binary.
- // +build !appengine
+```go
+// +build !appengine
- package main
+package main
- import "net/http"
+import "net/http"
- func main() {
- http.ListenAndServe("localhost:8080", nil)
- }
+func main() {
+ http.ListenAndServe("localhost:8080", nil)
+}
+```
To see a more complex hybrid app, take a look at the [present tool](https://godoc.org/golang.org/x/tools/present).
diff --git a/_content/blog/cgo.md b/_content/blog/cgo.md
index 8be46df..bd1f234 100644
--- a/_content/blog/cgo.md
+++ b/_content/blog/cgo.md
@@ -17,20 +17,22 @@
To lead with an example, here's a Go package that provides two functions -
`Random` and `Seed` - that wrap C's `random` and `srandom` functions.
- package rand
+```go
+package rand
- /*
- #include <stdlib.h>
- */
- import "C"
+/*
+#include <stdlib.h>
+*/
+import "C"
- func Random() int {
- return int(C.random())
- }
+func Random() int {
+ return int(C.random())
+}
- func Seed(i int) {
- C.srandom(C.uint(i))
- }
+func Seed(i int) {
+ C.srandom(C.uint(i))
+}
+```
Let's look at what's happening here, starting with the import statement.
@@ -49,24 +51,30 @@
It must be converted to a Go type before it can be used by Go code outside this package,
using an ordinary Go type conversion:
- func Random() int {
- return int(C.random())
- }
+```go
+func Random() int {
+ return int(C.random())
+}
+```
Here's an equivalent function that uses a temporary variable to illustrate the type conversion more explicitly:
- func Random() int {
- var r C.long = C.random()
- return int(r)
- }
+```go
+func Random() int {
+ var r C.long = C.random()
+ return int(r)
+}
+```
The `Seed` function does the reverse, in a way.
It takes a regular Go `int`, converts it to the C `unsigned int` type,
and passes it to the C function `srandom`.
- func Seed(i int) {
- C.srandom(C.uint(i))
- }
+```go
+func Seed(i int) {
+ C.srandom(C.uint(i))
+}
+```
Note that cgo knows the `unsigned int` type as `C.uint`;
see the [cgo documentation](/cmd/cgo) for a complete
@@ -74,10 +82,12 @@
The one detail of this example we haven't examined yet is the comment above the `import` statement.
- /*
- #include <stdlib.h>
- */
- import "C"
+```go
+/*
+#include <stdlib.h>
+*/
+import "C"
+```
Cgo recognizes this comment. Any lines starting with `#cgo` followed by
a space character are removed;
@@ -106,18 +116,20 @@
This next example implements a `Print` function that writes a string to
standard output using C's `fputs` function from the `stdio` library:
- package print
+```go
+package print
- // #include <stdio.h>
- // #include <stdlib.h>
- import "C"
- import "unsafe"
+// #include <stdio.h>
+// #include <stdlib.h>
+import "C"
+import "unsafe"
- func Print(s string) {
- cs := C.CString(s)
- C.fputs(cs, (*C.FILE)(C.stdout))
- C.free(unsafe.Pointer(cs))
- }
+func Print(s string) {
+ cs := C.CString(s)
+ C.fputs(cs, (*C.FILE)(C.stdout))
+ C.free(unsafe.Pointer(cs))
+}
+```
Memory allocations made by C code are not known to Go's memory manager.
When you create a C string with `C.CString` (or any C memory allocation)
@@ -131,11 +143,13 @@
is more complex than a single function call),
as in this rewrite of `Print`:
- func Print(s string) {
- cs := C.CString(s)
- defer C.free(unsafe.Pointer(cs))
- C.fputs(cs, (*C.FILE)(C.stdout))
- }
+```go
+func Print(s string) {
+ cs := C.CString(s)
+ defer C.free(unsafe.Pointer(cs))
+ C.fputs(cs, (*C.FILE)(C.stdout))
+}
+```
## Building cgo packages
diff --git a/_content/blog/chacha8rand.md b/_content/blog/chacha8rand.md
index d3068ea..e25cff8 100644
--- a/_content/blog/chacha8rand.md
+++ b/_content/blog/chacha8rand.md
@@ -144,21 +144,23 @@
on each step. The code looks like:
{{raw `
- func (r *rngSource) Uint64() uint64 {
- r.tap--
- if r.tap < 0 {
- r.tap += len(r.vec)
- }
-
- r.feed--
- if r.feed < 0 {
- r.feed += len(r.vec)
- }
-
- x := r.vec[r.feed] + r.vec[r.tap]
- r.vec[r.feed] = x
- return uint64(x)
+~~~go
+func (r *rngSource) Uint64() uint64 {
+ r.tap--
+ if r.tap < 0 {
+ r.tap += len(r.vec)
}
+
+ r.feed--
+ if r.feed < 0 {
+ r.feed += len(r.vec)
+ }
+
+ x := r.vec[r.feed] + r.vec[r.tap]
+ r.vec[r.feed] = x
+ return uint64(x)
+}
+~~~
`}}
Generating the next number is quite cheap: two subtractions, two conditional adds, two loads, one add, one store.
@@ -186,19 +188,21 @@
If the state `p.x` were a `uint128` (hypothetically), the code to compute the next value would be:
- const (
- pcgM = 0x2360ed051fc65da44385df649fccf645
- pcgA = 0x5851f42d4c957f2d14057b7ef767814f
- )
+```go
+const (
+ pcgM = 0x2360ed051fc65da44385df649fccf645
+ pcgA = 0x5851f42d4c957f2d14057b7ef767814f
+)
- type PCG struct {
- x uint128
- }
+type PCG struct {
+ x uint128
+}
- func (p *PCG) Uint64() uint64 {
- p.x = p.x * pcgM + pcgA
- return scramble(p.x)
- }
+func (p *PCG) Uint64() uint64 {
+ p.x = p.x * pcgM + pcgA
+ return scramble(p.x)
+}
+```
The entire state is a single 128-bit number,
and the update is a 128-bit multiply and add.
@@ -206,9 +210,11 @@
down to a 64-bit state.
The original PCG used (again using a hypothetical `uint128` type):
- func scramble(x uint128) uint64 {
- return bits.RotateLeft(uint64(x>>64) ^ uint64(x), -int(x>>122))
- }
+```go
+func scramble(x uint128) uint64 {
+ return bits.RotateLeft(uint64(x>>64) ^ uint64(x), -int(x>>122))
+}
+```
This code XORs the two halves of the 128-bit state together
and then rotates the result according to the top six bits of the state.
@@ -218,13 +224,15 @@
Go's PCG uses a new scramble function based on multiplication,
which mixes the bits more aggressively:
- func scramble(x uint128) uint64 {
- hi, lo := uint64(x>>64), uint64(x)
- hi ^= hi >> 32
- hi *= 0xda942042e4dd58b5
- hi ^= hi >> 48
- hi *= lo | 1
- }
+```go
+func scramble(x uint128) uint64 {
+ hi, lo := uint64(x>>64), uint64(x)
+ hi ^= hi >> 32
+ hi *= 0xda942042e4dd58b5
+ hi ^= hi >> 48
+ hi *= lo | 1
+}
+```
O'Neill calls PCG with this scrambler PCG-DXSM, for “double xorshift multiply.”
Numpy uses this form of PCG as well.
diff --git a/_content/blog/cleanups-and-weak.md b/_content/blog/cleanups-and-weak.md
index efaad18..c207d69 100644
--- a/_content/blog/cleanups-and-weak.md
+++ b/_content/blog/cleanups-and-weak.md
@@ -39,7 +39,7 @@
Let's consider an application that makes use of a memory-mapped file, and see
how cleanups can help.
-```
+```go
//go:build unix
type MemoryMappedFile struct {
@@ -166,7 +166,7 @@
file, we can clean up the map entry when nobody's using it anymore!
Let's see what this looks like.
-```
+```go
var cache sync.Map // map[string]weak.Pointer[MemoryMappedFile]
func NewCachedMemoryMappedFile(filename string) (*MemoryMappedFile, error) {
@@ -245,7 +245,7 @@
However, the advantage of the code we wrote above is that it can be rewritten
in a generic way!
-```
+```go
type Cache[K comparable, V any] struct {
create func(K) (*V, error)
m sync.Map
diff --git a/_content/blog/codelab-share.md b/_content/blog/codelab-share.md
index 95929e2..c8646b4 100644
--- a/_content/blog/codelab-share.md
+++ b/_content/blog/codelab-share.md
@@ -34,51 +34,55 @@
Consider a program that polls a list of URLs.
In a traditional threading environment, one might structure its data like so:
- type Resource struct {
- url string
- polling bool
- lastPolled int64
- }
+```go
+type Resource struct {
+ url string
+ polling bool
+ lastPolled int64
+}
- type Resources struct {
- data []*Resource
- lock *sync.Mutex
- }
+type Resources struct {
+ data []*Resource
+ lock *sync.Mutex
+}
+```
And then a Poller function (many of which would run in separate threads) might look something like this:
{{raw `
- func Poller(res *Resources) {
- for {
- // get the least recently-polled Resource
- // and mark it as being polled
- res.lock.Lock()
- var r *Resource
- for _, v := range res.data {
- if v.polling {
- continue
- }
- if r == nil || v.lastPolled < r.lastPolled {
- r = v
- }
- }
- if r != nil {
- r.polling = true
- }
- res.lock.Unlock()
- if r == nil {
- continue
- }
+~~~go
+func Poller(res *Resources) {
+ for {
+ // get the least recently-polled Resource
+ // and mark it as being polled
+ res.lock.Lock()
+ var r *Resource
+ for _, v := range res.data {
+ if v.polling {
+ continue
+ }
+ if r == nil || v.lastPolled < r.lastPolled {
+ r = v
+ }
+ }
+ if r != nil {
+ r.polling = true
+ }
+ res.lock.Unlock()
+ if r == nil {
+ continue
+ }
- // poll the URL
+ // poll the URL
- // update the Resource's polling and lastPolled
- res.lock.Lock()
- r.polling = false
- r.lastPolled = time.Nanoseconds()
- res.lock.Unlock()
- }
- }
+ // update the Resource's polling and lastPolled
+ res.lock.Lock()
+ r.polling = false
+ r.lastPolled = time.Nanoseconds()
+ res.lock.Unlock()
+ }
+}
+~~~
`}}
This function is about a page long, and requires more detail to make it complete.
@@ -92,16 +96,18 @@
and sends them to an output channel when they're done.
{{raw `
- type Resource string
+~~~go
+type Resource string
- func Poller(in, out chan *Resource) {
- for r := range in {
- // poll the URL
+func Poller(in, out chan *Resource) {
+ for r := range in {
+ // poll the URL
- // send the processed Resource to out
- out <- r
- }
- }
+ // send the processed Resource to out
+ out <- r
+ }
+}
+~~~
`}}
The delicate logic from the previous example is conspicuously absent,
diff --git a/_content/blog/comparable.md b/_content/blog/comparable.md
index 1bb08b0..e2648e2 100644
--- a/_content/blog/comparable.md
+++ b/_content/blog/comparable.md
@@ -15,7 +15,7 @@
If you're confused, you've come to the right place.
Consider the valid map declaration
-```Go
+```go
var lookupTable map[any]string
```
@@ -24,14 +24,14 @@
This works perfectly fine in Go.
On the other hand, before Go 1.20, the seemingly equivalent generic map type
-```Go
+```go
type genericLookupTable[K comparable, V any] map[K]V
```
could be used just like a regular map type, but produced a compile-time error when
`any` was used as the key type:
-```Go
+```go
var lookupTable genericLookupTable[any, string] // ERROR: any does not implement comparable (Go 1.18 and Go 1.19)
```
@@ -42,7 +42,7 @@
generics in the first place.
The proposed [`maps.Clone`](/issue/57436) function
-```Go
+```go
func Clone[M ~map[K]V, K comparable, V any](m M) M { … }
```
can be written but could not be used for a map such as `lookupTable` for the same reason
@@ -85,7 +85,7 @@
and the `~T` notation stands for "all types that have the underlying type `T`".
For instance, the interface
-```Go
+```go
interface {
~int | ~string
io.Writer
@@ -100,7 +100,7 @@
are sets of types.
For instance, we can write a generic `min` function
-```Go
+```go
func min[P interface{ ~int64 | ~float64 }](x, y P) P
```
@@ -113,7 +113,7 @@
allows us to [omit the enclosing `interface{}`](/ref/spec#General_interfaces),
leading to the compact and more idiomatic
-```Go
+```go
func min[P ~int64 | ~float64](x, y P) P { … }
```
@@ -181,7 +181,7 @@
But if we try to enter a value with a key that does not support `==`, say
a slice value, we get a run-time panic:
-```Go
+```go
lookupTable[[]int{}] = "slice" // PANIC: runtime error: hash of unhashable type []int
```
@@ -199,7 +199,7 @@
But the type set of `any` is larger than (not a subset of) the type set of `comparable`
and therefore does not implement `comparable`.
-```Go
+```go
var lookupTable GenericLookupTable[any, string] // ERROR: any does not implement comparable (Go 1.18 and Go 1.19)
```
@@ -218,7 +218,7 @@
But this leads to inconsistencies with the type set model.
Consider the following example:
-```Go
+```go
func f[Q comparable]() { … }
func g[P any]() {
@@ -288,7 +288,7 @@
Let's revisit our previous example:
-```Go
+```go
func f[Q comparable]() { … }
func g[P any]() {
@@ -349,7 +349,7 @@
comparable type argument and cause a panic.
In Go 1.20 we can now declare
-```Go
+```go
var lookupTable genericLookupTable[any, string]
```
@@ -369,14 +369,14 @@
We can use this knowledge to craft a compile-time assertion of sorts for
a given type `T`:
-```Go
+```go
type T struct { … }
```
We want to assert that `T` is strictly comparable.
It's tempting to write something like:
-```Go
+```go
// isComparable may be instantiated with any type that supports ==
// including types that are not strictly comparable because of the
// exception for constraint satisfaction.
@@ -394,7 +394,7 @@
We can work around this problem by using `T` not as a type argument,
but as a type constraint:
-```Go
+```go
func _[P T]() {
_ = isComparable[P] // P supports == only if T is strictly comparable
}
diff --git a/_content/blog/compat.md b/_content/blog/compat.md
index 33549a0..ed8cc9e 100644
--- a/_content/blog/compat.md
+++ b/_content/blog/compat.md
@@ -63,13 +63,15 @@
For example, here’s a program someone has written
that we can’t break:
- package main
+```go
+package main
- import "os"
+import "os"
- func main() {
- os.Stdout.WriteString("hello, world\n")
- }
+func main() {
+ os.Stdout.WriteString("hello, world\n")
+}
+```
We can’t remove the package `os`;
we can’t remove the global variable `os.Stdout`, which is an `*os.File`;
@@ -81,17 +83,19 @@
Suppose we want to make it an interface with the same methods.
The program we just saw wouldn’t break, but this one would:
- package main
+```go
+package main
- import "os"
+import "os"
- func main() {
- greet(os.Stdout)
- }
+func main() {
+ greet(os.Stdout)
+}
- func greet(f *os.File) {
- f.WriteString(“hello, world\n”)
- }
+func greet(f *os.File) {
+ f.WriteString(“hello, world\n”)
+}
+```
This program passes `os.Stdout` to a function named `greet`
that requires an argument of type `*os.File`.
@@ -148,14 +152,16 @@
Here is some code that runs fine in Go 1:
- package main
+```go
+package main
- import "net"
+import "net"
- var myAddr = &net.TCPAddr{
- net.IPv4(18, 26, 4, 9),
- 80,
- }
+var myAddr = &net.TCPAddr{
+ net.IPv4(18, 26, 4, 9),
+ 80,
+}
+```
Package `main` declares a global variable `myAddr`,
which is a composite literal of type `net.TCPAddr`.
@@ -171,10 +177,12 @@
The fix is to rewrite the program using tagged literals,
so that it builds in both versions of Go:
- var myAddr = &net.TCPAddr{
- IP: net.IPv4(18, 26, 4, 9),
- Port: 80,
- }
+```go
+var myAddr = &net.TCPAddr{
+ IP: net.IPv4(18, 26, 4, 9),
+ Port: 80,
+}
+```
Since this literal doesn’t specify a value for `Zone`, it will use the
zero value (an empty string in this case).
@@ -205,13 +213,15 @@
That broke a handful of tests inside Google that
were schematically like this one:
- func TestSaveTime(t *testing.T) {
- t1 := time.Now()
- save(t1)
- if t2 := load(); t2 != t1 {
- t.Fatalf("load() = %v, want %v", t1, t2)
- }
+```go
+func TestSaveTime(t *testing.T) {
+ t1 := time.Now()
+ save(t1)
+ if t2 := load(); t2 != t1 {
+ t.Fatalf("load() = %v, want %v", t1, t2)
}
+}
+```
This code calls `time.Now`
and then round-trips the result
@@ -269,13 +279,15 @@
Here's an example program
that sorts a list of colors by length of name:
- colors := strings.Fields(
- `black white red orange yellow green blue indigo violet`)
- sort.Sort(ByLen(colors))
- fmt.Println(colors)
+```go
+colors := strings.Fields(
+ `black white red orange yellow green blue indigo violet`)
+sort.Sort(ByLen(colors))
+fmt.Println(colors)
- Go 1.5: [red blue green white black yellow orange indigo violet]
- Go 1.6: [red blue white green black orange yellow indigo violet]
+Go 1.5: [red blue green white black yellow orange indigo violet]
+Go 1.6: [red blue white green black orange yellow indigo violet]
+```
Changing sort algorithms often changes
how equal elements are ordered,
@@ -487,7 +499,9 @@
If it says `go 1.21` or later, `panic(nil)` turns into a panic with a `runtime.PanicNilError`.
And the version-based default can be overridden explicitly by adding a line like this to package main:
- //go:debug panicnil=1
+```go
+//go:debug panicnil=1
+```
This combination of features means that programs can update to newer toolchains
while preserving the behaviors of the earlier toolchains they used,
diff --git a/_content/blog/concurrency-timeouts.md b/_content/blog/concurrency-timeouts.md
index 66fc760..1db316d 100644
--- a/_content/blog/concurrency-timeouts.md
+++ b/_content/blog/concurrency-timeouts.md
@@ -20,11 +20,13 @@
that sleeps before sending on the channel:
{{raw `
- timeout := make(chan bool, 1)
- go func() {
- time.Sleep(1 * time.Second)
- timeout <- true
- }()
+~~~go
+timeout := make(chan bool, 1)
+go func() {
+ time.Sleep(1 * time.Second)
+ timeout <- true
+}()
+~~~
`}}
We can then use a `select` statement to receive from either `ch` or `timeout`.
@@ -32,12 +34,14 @@
the timeout case is selected and the attempt to read from ch is abandoned.
{{raw `
- select {
- case <-ch:
- // a read from ch has occurred
- case <-timeout:
- // the read from ch has timed out
- }
+~~~go
+select {
+case <-ch:
+ // a read from ch has occurred
+case <-timeout:
+ // the read from ch has timed out
+}
+~~~
`}}
The `timeout` channel is buffered with space for 1 value,
@@ -60,18 +64,20 @@
It queries each of the databases in parallel and returns the first response it receives:
{{raw `
- func Query(conns []Conn, query string) Result {
- ch := make(chan Result)
- for _, conn := range conns {
- go func(c Conn) {
- select {
- case ch <- c.DoQuery(query):
- default:
- }
- }(conn)
- }
- return <-ch
- }
+~~~go
+func Query(conns []Conn, query string) Result {
+ ch := make(chan Result)
+ for _, conn := range conns {
+ go func(c Conn) {
+ select {
+ case ch <- c.DoQuery(query):
+ default:
+ }
+ }(conn)
+ }
+ return <-ch
+}
+~~~
`}}
In this example, the closure does a non-blocking send,
diff --git a/_content/blog/constants.md b/_content/blog/constants.md
index 4ccae1b..80d17b7 100644
--- a/_content/blog/constants.md
+++ b/_content/blog/constants.md
@@ -44,8 +44,10 @@
If you want to add `i` and `u`, you must be explicit about what you want the result to be.
Given
- var u uint
- var i int
+```go
+var u uint
+var i int
+```
you can write either `uint(i)+u` or `i+int(u)`,
with both the meaning and type of the addition clearly expressed,
@@ -100,7 +102,9 @@
but for the purpose of this discussion they have all the same properties.)
Here is a string constant:
- "Hello, 世界"
+```go
+"Hello, 世界"
+```
(For much more detail about the representation and interpretation of strings,
see [this blog post](/blog/strings).)
@@ -113,7 +117,9 @@
Yes, it's a string, but it's not a Go value of type `string`.
It remains an untyped string constant even when given a name:
- const hello = "Hello, 世界"
+```go
+const hello = "Hello, 世界"
+```
After this declaration, `hello` is also an untyped string constant.
An untyped constant is just a value, one not yet given a defined type that
@@ -124,7 +130,9 @@
So what, then, is a _typed_ string constant?
It's one that's been given a type, like this:
- const typedHello string = "Hello, 世界"
+```go
+const typedHello string = "Hello, 世界"
+```
Notice that the declaration of `typedHello` has an explicit `string` type before the equals sign.
This means that `typedHello` has Go type `string`, and cannot be assigned to a Go variable of a different type.
@@ -150,11 +158,15 @@
assigning it to a typed variable does not cause a type error.
That is, we can write
- m = "Hello, 世界"
+```go
+m = "Hello, 世界"
+```
or
- m = hello
+```go
+m = hello
+```
because, unlike the typed constants `typedHello` and `myStringHello`,
the untyped constants `"Hello, 世界"` and `hello` _have no type_.
@@ -168,22 +180,30 @@
As a Go programmer, you have certainly seen many declarations like
- str := "Hello, 世界"
+```go
+str := "Hello, 世界"
+```
and by now you might be asking, "if the constant is untyped, how does `str` get a type in this variable declaration?"
The answer is that an untyped constant has a default type,
an implicit type that it transfers to a value if a type is needed where none is provided.
For untyped string constants, that default type is obviously `string`, so
- str := "Hello, 世界"
+```go
+str := "Hello, 世界"
+```
or
- var str = "Hello, 世界"
+```go
+var str = "Hello, 世界"
+```
means exactly the same as
- var str string = "Hello, 世界"
+```go
+var str string = "Hello, 世界"
+```
One way to think about untyped constants is that they live in a kind of
ideal space of values,
@@ -202,7 +222,9 @@
The signature of `fmt.Printf` is
- func Printf(format string, a ...interface{}) (n int, err error)
+```go
+func Printf(format string, a ...interface{}) (n int, err error)
+```
which is to say its arguments (after the format string) are interface values.
What happens when `fmt.Printf` is called with an untyped constant is that an interface value is created
@@ -291,7 +313,9 @@
The constants defined in the [math](/pkg/math) package are given with many more digits than are
available in a `float64`. Here is the definition of `math.Pi`:
- Pi = 3.14159265358979323846264338327950288419716939937510582097494459
+```go
+Pi = 3.14159265358979323846264338327950288419716939937510582097494459
+```
When that value is assigned to a variable,
some of the precision will be lost;
@@ -358,9 +382,11 @@
The same example could be built for any of the integer types, which are:
- int int8 int16 int32 int64
- uint uint8 uint16 uint32 uint64
- uintptr
+```go
+int int8 int16 int32 int64
+uint uint8 uint16 uint32 uint64
+uintptr
+```
(plus the aliases `byte` for `uint8` and `rune` for `int32`).
That's a lot, but the pattern in the way constants work should be familiar
@@ -378,9 +404,11 @@
Here are several different ways to initialize a `uint`;
all are equivalent, but all must mention the type explicitly for the result to be unsigned.
- var u uint = 17
- var u = uint(17)
- u := uint(17)
+```go
+var u uint = 17
+var u = uint(17)
+u := uint(17)
+```
Similarly to the range issue mentioned in the section on floating-point values,
not all integer values can fit in all integer types.
@@ -409,7 +437,9 @@
If we were talking about `uint32` rather than `uint`, we could write
{{raw `
- const MaxUint32 = 1<<32 - 1
+~~~go
+const MaxUint32 = 1<<32 - 1
+~~~
`}}
but we want `uint`, not `uint32`.
@@ -480,13 +510,15 @@
But as long as we stay in the world of numeric constants, we can mix and match values as we like.
All these constants have numeric value 1:
- 1
- 1.000
- 1e3-99.0*10-9
- '\x01'
- '\u0001'
- 'b' - 'a'
- 1.0+3i-3.0i
+```go
+1
+1.000
+1e3-99.0*10-9
+'\x01'
+'\u0001'
+'b' - 'a'
+1.0+3i-3.0i
+```
Therefore, although they have different implicit default types,
written as untyped constants they can be assigned to a variable of any numeric type:
@@ -506,15 +538,21 @@
the same expression to mix floating-point and integer variables,
or even `int` and `int32` variables, it is fine to write
- sqrt2 := math.Sqrt(2)
+```go
+sqrt2 := math.Sqrt(2)
+```
or
- const millisecond = time.Second/1e3
+```go
+const millisecond = time.Second/1e3
+```
or
- bigBufferWithHeader := make([]byte, 512+1e6)
+```go
+bigBufferWithHeader := make([]byte, 512+1e6)
+```
and have the results mean what you expect.
diff --git a/_content/blog/context-and-structs.md b/_content/blog/context-and-structs.md
index d3368ea..a50f45e 100644
--- a/_content/blog/context-and-structs.md
+++ b/_content/blog/context-and-structs.md
@@ -22,7 +22,7 @@
To understand the advice to not store context in structs, let's consider the preferred context-as-argument approach:
-```
+```go
// Worker fetches and adds works to a remote work orchestration server.
type Worker struct { /* … */ }
@@ -47,7 +47,7 @@
Let's inspect again the `Worker` example above with the disfavored context-in-struct approach. The problem with it is that when you store the context in a struct, you obscure lifetime to the callers, or worse intermingle two scopes together in unpredictable ways:
-```
+```go
type Worker struct {
ctx context.Context
}
@@ -84,21 +84,21 @@
The `net/http` package chose the context-in-struct approach, which provides a useful case study. Let's look at `net/http`'s `Do`. Prior to the introduction of `context.Context`, `Do` was defined as follows:
-```
+```go
// Do sends an HTTP request and returns an HTTP response [...]
func (c *Client) Do(req *Request) (*Response, error)
```
After Go 1.7, `Do` might have looked like the following, if not for the fact that it would break backwards compatibility:
-```
+```go
// Do sends an HTTP request and returns an HTTP response [...]
func (c *Client) Do(ctx context.Context, req *Request) (*Response, error)
```
But, preserving the backwards compatibility and adhering to the [Go 1 promise of compatibility](/doc/go1compat) is crucial for the standard library. So, instead, the maintainers chose to add a `context.Context` on the `http.Request` struct in order to allow support `context.Context` without breaking backwards compatibility:
-```
+```go
// A Request represents an HTTP request received by a server or to be sent by a client.
// ...
type Request struct {
@@ -125,7 +125,7 @@
When retrofitting your API to support context, it may make sense to add a `context.Context` to a struct, as above. However, remember to first consider duplicating your functions, which allows retrofitting `context.Context` in a backwards compatibility without sacrificing utility and comprehension. For example:
-```
+```go
// Call uses context.Background internally; to specify the context, use
// CallContext.
func (c *Client) Call() error {
diff --git a/_content/blog/contributor-workshop.md b/_content/blog/contributor-workshop.md
index a6daac1..f7f6220 100644
--- a/_content/blog/contributor-workshop.md
+++ b/_content/blog/contributor-workshop.md
@@ -275,14 +275,16 @@
file. They follow the format of test cases followed by "Output" commented out
and then the answers to the tests. For example:
- func ExampleRegexp_FindString() {
- re := regexp.MustCompile("fo.?")
- fmt.Printf("%q\n", re.FindString("seafood"))
- fmt.Printf("%q\n", re.FindString("meat"))
- // Output:
- // "foo"
- // ""
- }
+```go
+func ExampleRegexp_FindString() {
+ re := regexp.MustCompile("fo.?")
+ fmt.Printf("%q\n", re.FindString("seafood"))
+ fmt.Printf("%q\n", re.FindString("meat"))
+ // Output:
+ // "foo"
+ // ""
+}
+```
Kind of cool, right?? I followed Francesc's lead and added a function
`ExampleQuoteMeta` and added a few I thought would be helpful. From there it's
diff --git a/_content/blog/coretypes.md b/_content/blog/coretypes.md
index 33874e6..13e9b7b 100644
--- a/_content/blog/coretypes.md
+++ b/_content/blog/coretypes.md
@@ -39,7 +39,7 @@
For instance, the type set described by the interface
-```Go
+```go
type Constraint interface {
~[]byte | ~string
Hash() uint64
@@ -58,7 +58,7 @@
These rules make it possible to index the generic variable `s` below ([playground](/play/p/M1LYKm3x3IB)):
-```Go
+```go
func at[bytestring Constraint](s bytestring, i int) byte {
return s[i]
}
diff --git a/_content/blog/cover.md b/_content/blog/cover.md
index f05e363..1e664a3 100644
--- a/_content/blog/cover.md
+++ b/_content/blog/cover.md
@@ -284,7 +284,9 @@
opening brace looks like it belongs outside the block.
A more interesting consequence is that in an expression like
- f() && g()
+```go
+f() && g()
+```
there is no attempt to separately instrument the calls to `f` and `g`, Regardless of
the facts it will always look like they both ran the same
diff --git a/_content/blog/deadcode.md b/_content/blog/deadcode.md
index 061fdf3..a48f85c 100644
--- a/_content/blog/deadcode.md
+++ b/_content/blog/deadcode.md
@@ -39,7 +39,7 @@
go 1.21
```
-```
+```go
package main
import "fmt"
diff --git a/_content/blog/declaration-syntax.md b/_content/blog/declaration-syntax.md
index 6317ee2..2df5705 100644
--- a/_content/blog/declaration-syntax.md
+++ b/_content/blog/declaration-syntax.md
@@ -122,9 +122,11 @@
Go takes its cue from here, but in the interests of brevity it drops the
colon and removes some of the keywords:
- x int
- p *int
- a [3]int
+```go
+x int
+p *int
+a [3]int
+```
There is no direct correspondence between the look of [3]int and how to
use a in an expression.
@@ -134,7 +136,9 @@
Now consider functions. Let's transcribe the declaration for main as it would read in Go,
although the real main function in Go takes no arguments:
- func main(argc int, argv []string) int
+```go
+func main(argc int, argv []string) int
+```
Superficially that's not much different from C,
other than the change from `char` arrays to strings,
@@ -144,24 +148,32 @@
Drop the parameter names and it's just as clear - they're always first so there's no confusion.
- func main(int, []string) int
+```go
+func main(int, []string) int
+```
One merit of this left-to-right style is how well it works as the types
become more complex.
Here's a declaration of a function variable (analogous to a function pointer in C):
- f func(func(int,int) int, int) int
+```go
+f func(func(int,int) int, int) int
+```
Or if f returns a function:
- f func(func(int,int) int, int) func(int, int) int
+```go
+f func(func(int,int) int, int) func(int, int) int
+```
It still reads clearly, from left to right,
and it's always obvious which name is being declared - the name comes first.
The distinction between type and expression syntax makes it easy to write and invoke closures in Go:
- sum := func(a, b int) int { return a+b } (3, 4)
+```go
+sum := func(a, b int) int { return a+b } (3, 4)
+```
## Pointers
@@ -170,36 +182,48 @@
Go's type syntax puts the brackets on the left of the type but the expression
syntax puts them on the right of the expression:
- var a []int
- x = a[1]
+```go
+var a []int
+x = a[1]
+```
For familiarity, Go's pointers use the \* notation from C,
but we could not bring ourselves to make a similar reversal for pointer types.
Thus pointers work like this
- var p *int
- x = *p
+```go
+var p *int
+x = *p
+```
We couldn't say
- var p *int
- x = p*
+```go
+var p *int
+x = p*
+```
because that postfix \* would conflate with multiplication. We could have used the Pascal ^, for example:
- var p ^int
- x = p^
+```go
+var p ^int
+x = p^
+```
and perhaps we should have (and chosen another operator for xor),
because the prefix asterisk on both types and expressions complicates things
in a number of ways.
For instance, although one can write
- []int("hi")
+```go
+[]int("hi")
+```
as a conversion, one must parenthesize the type if it starts with a \*:
- (*int)(nil)
+```go
+(*int)(nil)
+```
Had we been willing to give up \* as pointer syntax, those parentheses would be unnecessary.
diff --git a/_content/blog/deconstructing-type-parameters.md b/_content/blog/deconstructing-type-parameters.md
index ca1dd5c..c7e60b0 100644
--- a/_content/blog/deconstructing-type-parameters.md
+++ b/_content/blog/deconstructing-type-parameters.md
@@ -11,7 +11,7 @@
The [`slices.Clone`](https://pkg.go.dev/slices#Clone) function is
pretty simple: it makes a copy of a slice of any type.
-```Go
+```go
func Clone[S ~[]E, E any](s S) S {
return append(s[:0:0], s...)
}
@@ -31,7 +31,7 @@
This is not the one in the `slices` package.
We want to take a slice of any element type, and return a new slice.
-```Go
+```go
func Clone1[E any](s []E) []E {
// body omitted
}
@@ -46,7 +46,7 @@
However, there is a problem.
Named slice types are not common in Go, but people do use them.
-```Go
+```go
// MySlice is a slice of strings with a special String method.
type MySlice []string
@@ -59,7 +59,7 @@
Let's say that we want to make a copy of a `MySlice` and then get the
printable version, but with the strings in sorted order.
-```Go
+```go
func PrintSorted(ms MySlice) string {
c := Clone1(ms)
slices.Sort(c)
@@ -77,7 +77,7 @@
We can see the problem if we manually instantiate `Clone1` by
replacing the type parameter with the type argument.
-```Go
+```go
func InstantiatedClone1(s []string) []string
```
@@ -98,7 +98,7 @@
We know that it has to look something like this.
-```Go
+```go
func Clone2[S ?](s S) S // INVALID
```
@@ -119,7 +119,7 @@
We don't care what the slice element type is, so let's just call it
`E`, as we did with `Clone1`.
-```Go
+```go
func Clone3[S []E](s S) S // INVALID
```
@@ -128,7 +128,7 @@
be a type parameter itself.
Since it can be any type, its constraint is `any`.
-```Go
+```go
func Clone4[S []E, E any](s S) S
```
@@ -151,7 +151,7 @@
As the error message hints, the answer is to add a `~`.
-```Go
+```go
func Clone5[S ~[]E, E any](s S) S
```
@@ -227,7 +227,7 @@
how actually using `slices.Clone` is simplified by type inference.
Remember, the signature of `Clone` is
-```Go
+```go
func Clone[S ~[]E, E any](s S) S
```
@@ -240,13 +240,13 @@
This means that we can write
-```Go
+```go
c := Clone(ms)
```
without having to write
-```Go
+```go
c := Clone[MySlice, string](ms)
```
@@ -259,13 +259,13 @@
That is, we can write
-```Go
+```go
myClone := Clone[MySlice]
```
without having to write
-```Go
+```go
myClone := Clone[MySlice, string]
```
@@ -279,7 +279,7 @@
For example, here is the signature for `maps.Clone`.
-```Go
+```go
func Clone[M ~map[K]V, K comparable, V any](m M) M
```
@@ -291,7 +291,7 @@
a map key type.
We can constrain the component types any way we like.
-```Go
+```go
func WithStrings[S ~[]E, E interface { String() string }](s S) (S, []string)
```
diff --git a/_content/blog/defer-panic-and-recover.md b/_content/blog/defer-panic-and-recover.md
index a353979..421275d 100644
--- a/_content/blog/defer-panic-and-recover.md
+++ b/_content/blog/defer-panic-and-recover.md
@@ -26,22 +26,24 @@
For example, let's look at a function that opens two files and copies the contents of one file to the other:
- func CopyFile(dstName, srcName string) (written int64, err error) {
- src, err := os.Open(srcName)
- if err != nil {
- return
- }
+```go
+func CopyFile(dstName, srcName string) (written int64, err error) {
+ src, err := os.Open(srcName)
+ if err != nil {
+ return
+ }
- dst, err := os.Create(dstName)
- if err != nil {
- return
- }
+ dst, err := os.Create(dstName)
+ if err != nil {
+ return
+ }
- written, err = io.Copy(dst, src)
- dst.Close()
- src.Close()
- return
- }
+ written, err = io.Copy(dst, src)
+ dst.Close()
+ src.Close()
+ return
+}
+```
This works, but there is a bug. If the call to os.Create fails,
the function will return without closing the source file.
@@ -50,21 +52,23 @@
noticed and resolved.
By introducing defer statements we can ensure that the files are always closed:
- func CopyFile(dstName, srcName string) (written int64, err error) {
- src, err := os.Open(srcName)
- if err != nil {
- return
- }
- defer src.Close()
+```go
+func CopyFile(dstName, srcName string) (written int64, err error) {
+ src, err := os.Open(srcName)
+ if err != nil {
+ return
+ }
+ defer src.Close()
- dst, err := os.Create(dstName)
- if err != nil {
- return
- }
- defer dst.Close()
+ dst, err := os.Create(dstName)
+ if err != nil {
+ return
+ }
+ defer dst.Close()
- return io.Copy(dst, src)
- }
+ return io.Copy(dst, src)
+}
+```
Defer statements allow us to think about closing each file right after opening it,
guaranteeing that, regardless of the number of return statements in the function,
@@ -77,23 +81,27 @@
In this example, the expression "i" is evaluated when the Println call is deferred.
The deferred call will print "0" after the function returns.
- func a() {
- i := 0
- defer fmt.Println(i)
- i++
- return
- }
+```go
+func a() {
+ i := 0
+ defer fmt.Println(i)
+ i++
+ return
+}
+```
2. _Deferred function calls are executed in Last In First Out order after the surrounding function returns._
This function prints "3210":
{{raw `
- func b() {
- for i := 0; i < 4; i++ {
- defer fmt.Print(i)
- }
- }
+~~~go
+func b() {
+ for i := 0; i < 4; i++ {
+ defer fmt.Print(i)
+ }
+}
+~~~
`}}
3. _Deferred functions may read and assign to the returning function's named return values._
@@ -102,10 +110,12 @@
the surrounding function returns.
Thus, this function returns 2:
- func c() (i int) {
- defer func() { i++ }()
- return 1
- }
+```go
+func c() (i int) {
+ defer func() { i++ }()
+ return 1
+}
+```
This is convenient for modifying the error return value of a function; we will see an example of this shortly.
@@ -128,35 +138,37 @@
Here's an example program that demonstrates the mechanics of panic and defer:
- package main
+```go
+package main
- import "fmt"
+import "fmt"
- func main() {
- f()
- fmt.Println("Returned normally from f.")
- }
+func main() {
+ f()
+ fmt.Println("Returned normally from f.")
+}
- func f() {
- defer func() {
- if r := recover(); r != nil {
- fmt.Println("Recovered in f", r)
- }
- }()
- fmt.Println("Calling g.")
- g(0)
- fmt.Println("Returned normally from g.")
- }
+func f() {
+ defer func() {
+ if r := recover(); r != nil {
+ fmt.Println("Recovered in f", r)
+ }
+ }()
+ fmt.Println("Calling g.")
+ g(0)
+ fmt.Println("Returned normally from g.")
+}
- func g(i int) {
- if i > 3 {
- fmt.Println("Panicking!")
- panic(fmt.Sprintf("%v", i))
- }
- defer fmt.Println("Defer in g", i)
- fmt.Println("Printing in g", i)
- g(i + 1)
- }
+func g(i int) {
+ if i > 3 {
+ fmt.Println("Panicking!")
+ panic(fmt.Sprintf("%v", i))
+ }
+ defer fmt.Println("Defer in g", i)
+ fmt.Println("Printing in g", i)
+ g(i + 1)
+}
+```
The function g takes the int i, and panics if i is greater than 3,
or else it calls itself with the argument i+1.
@@ -213,13 +225,17 @@
Other uses of **defer** (beyond the file.Close example given earlier) include releasing a mutex:
- mu.Lock()
- defer mu.Unlock()
+```go
+mu.Lock()
+defer mu.Unlock()
+```
printing a footer:
- printHeader()
- defer printFooter()
+```go
+printHeader()
+defer printFooter()
+```
and more.
diff --git a/_content/blog/error-handling-and-go.md b/_content/blog/error-handling-and-go.md
index 1250278..e4c2874 100644
--- a/_content/blog/error-handling-and-go.md
+++ b/_content/blog/error-handling-and-go.md
@@ -19,16 +19,20 @@
For example, the `os.Open` function returns a non-nil `error` value when
it fails to open a file.
- func Open(name string) (file *File, err error)
+```go
+func Open(name string) (file *File, err error)
+```
The following code uses `os.Open` to open a file.
If an error occurs it calls `log.Fatal` to print the error message and stop.
- f, err := os.Open("filename.ext")
- if err != nil {
- log.Fatal(err)
- }
- // do something with the open *File f
+```go
+f, err := os.Open("filename.ext")
+if err != nil {
+ log.Fatal(err)
+}
+// do something with the open *File f
+```
You can get a lot done in Go knowing just this about the `error` type,
but in this article we'll take a closer look at `error` and discuss some
@@ -40,9 +44,11 @@
value that can describe itself as a string.
Here is the interface's declaration:
- type error interface {
- Error() string
- }
+```go
+type error interface {
+ Error() string
+}
+```
The `error` type, as with all built in types,
is [predeclared](/doc/go_spec.html#Predeclared_identifiers)
@@ -51,33 +57,39 @@
The most commonly-used `error` implementation is the [errors](/pkg/errors/)
package's unexported `errorString` type.
- // errorString is a trivial implementation of error.
- type errorString struct {
- s string
- }
+```go
+// errorString is a trivial implementation of error.
+type errorString struct {
+ s string
+}
- func (e *errorString) Error() string {
- return e.s
- }
+func (e *errorString) Error() string {
+ return e.s
+}
+```
You can construct one of these values with the `errors.New` function.
It takes a string that it converts to an `errors.errorString` and returns
as an `error` value.
- // New returns an error that formats as the given text.
- func New(text string) error {
- return &errorString{text}
- }
+```go
+// New returns an error that formats as the given text.
+func New(text string) error {
+ return &errorString{text}
+}
+```
Here's how you might use `errors.New`:
{{raw `
- func Sqrt(f float64) (float64, error) {
- if f < 0 {
- return 0, errors.New("math: square root of negative number")
- }
- // implementation
- }
+~~~go
+func Sqrt(f float64) (float64, error) {
+ if f < 0 {
+ return 0, errors.New("math: square root of negative number")
+ }
+ // implementation
+}
+~~~
`}}
A caller passing a negative argument to `Sqrt` receives a non-nil `error`
@@ -86,10 +98,12 @@
square root of...") by calling the `error`'s `Error` method,
or by just printing it:
- f, err := Sqrt(-1)
- if err != nil {
- fmt.Println(err)
- }
+```go
+f, err := Sqrt(-1)
+if err != nil {
+ fmt.Println(err)
+}
+```
The [fmt](/pkg/fmt/) package formats an `error` value by calling its `Error() string` method.
@@ -103,9 +117,11 @@
created by `errors.New`.
{{raw `
- if f < 0 {
- return 0, fmt.Errorf("math: square root of negative number %g", f)
- }
+~~~go
+if f < 0 {
+ return 0, fmt.Errorf("math: square root of negative number %g", f)
+}
+~~~
`}}
In many cases `fmt.Errorf` is good enough,
@@ -117,11 +133,13 @@
We can enable that by defining a new error implementation instead of using
`errors.errorString`:
- type NegativeSqrtError float64
+```go
+type NegativeSqrtError float64
- func (f NegativeSqrtError) Error() string {
- return fmt.Sprintf("math: square root of negative number %g", float64(f))
- }
+func (f NegativeSqrtError) Error() string {
+ return fmt.Sprintf("math: square root of negative number %g", float64(f))
+}
+```
A sophisticated caller can then use a [type assertion](/doc/go_spec.html#Type_assertions)
to check for a `NegativeSqrtError` and handle it specially,
@@ -132,23 +150,27 @@
package specifies a `SyntaxError` type that the `json.Decode` function returns
when it encounters a syntax error parsing a JSON blob.
- type SyntaxError struct {
- msg string // description of error
- Offset int64 // error occurred after reading Offset bytes
- }
+```go
+type SyntaxError struct {
+ msg string // description of error
+ Offset int64 // error occurred after reading Offset bytes
+}
- func (e *SyntaxError) Error() string { return e.msg }
+func (e *SyntaxError) Error() string { return e.msg }
+```
The `Offset` field isn't even shown in the default formatting of the error,
but callers can use it to add file and line information to their error messages:
- if err := dec.Decode(&val); err != nil {
- if serr, ok := err.(*json.SyntaxError); ok {
- line, col := findLine(f, serr.Offset)
- return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
- }
- return err
- }
+```go
+if err := dec.Decode(&val); err != nil {
+ if serr, ok := err.(*json.SyntaxError); ok {
+ line, col := findLine(f, serr.Offset)
+ return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
+ }
+ return err
+}
+```
(This is a slightly simplified version of some [actual code](https://github.com/camlistore/go4/blob/03efcb870d84809319ea509714dd6d19a1498483/jsonconfig/eval.go#L123-L135)
from the [Camlistore](http://camlistore.org) project.)
@@ -159,26 +181,30 @@
following the usual convention, but some of the error implementations have
additional methods defined by the `net.Error` interface:
- package net
+```go
+package net
- type Error interface {
- error
- Timeout() bool // Is the error a timeout?
- Temporary() bool // Is the error temporary?
- }
+type Error interface {
+ error
+ Timeout() bool // Is the error a timeout?
+ Temporary() bool // Is the error temporary?
+}
+```
Client code can test for a `net.Error` with a type assertion and then distinguish
transient network errors from permanent ones.
For instance, a web crawler might sleep and retry when it encounters a temporary
error and give up otherwise.
- if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
- time.Sleep(1e9)
- continue
- }
- if err != nil {
- log.Fatal(err)
- }
+```go
+if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
+ time.Sleep(1e9)
+ continue
+}
+if err != nil {
+ log.Fatal(err)
+}
+```
## Simplifying repetitive error handling
@@ -192,22 +218,24 @@
application with an HTTP handler that retrieves a record from the datastore
and formats it with a template.
- func init() {
- http.HandleFunc("/view", viewRecord)
- }
+```go
+func init() {
+ http.HandleFunc("/view", viewRecord)
+}
- func viewRecord(w http.ResponseWriter, r *http.Request) {
- c := appengine.NewContext(r)
- key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
- record := new(Record)
- if err := datastore.Get(c, key, record); err != nil {
- http.Error(w, err.Error(), 500)
- return
- }
- if err := viewTemplate.Execute(w, record); err != nil {
- http.Error(w, err.Error(), 500)
- }
- }
+func viewRecord(w http.ResponseWriter, r *http.Request) {
+ c := appengine.NewContext(r)
+ key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
+ record := new(Record)
+ if err := datastore.Get(c, key, record); err != nil {
+ http.Error(w, err.Error(), 500)
+ return
+ }
+ if err := viewTemplate.Execute(w, record); err != nil {
+ http.Error(w, err.Error(), 500)
+ }
+}
+```
This function handles errors returned by the `datastore.Get` function and
`viewTemplate`'s `Execute` method.
@@ -219,19 +247,23 @@
To reduce the repetition we can define our own HTTP `appHandler` type that includes an `error` return value:
- type appHandler func(http.ResponseWriter, *http.Request) error
+```go
+type appHandler func(http.ResponseWriter, *http.Request) error
+```
Then we can change our `viewRecord` function to return errors:
- func viewRecord(w http.ResponseWriter, r *http.Request) error {
- c := appengine.NewContext(r)
- key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
- record := new(Record)
- if err := datastore.Get(c, key, record); err != nil {
- return err
- }
- return viewTemplate.Execute(w, record)
- }
+```go
+func viewRecord(w http.ResponseWriter, r *http.Request) error {
+ c := appengine.NewContext(r)
+ key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
+ record := new(Record)
+ if err := datastore.Get(c, key, record); err != nil {
+ return err
+ }
+ return viewTemplate.Execute(w, record)
+}
+```
This is simpler than the original version,
but the [http](/pkg/net/http/) package doesn't understand
@@ -239,11 +271,13 @@
To fix this we can implement the `http.Handler` interface's `ServeHTTP`
method on `appHandler`:
- func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if err := fn(w, r); err != nil {
- http.Error(w, err.Error(), 500)
- }
- }
+```go
+func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if err := fn(w, r); err != nil {
+ http.Error(w, err.Error(), 500)
+ }
+}
+```
The `ServeHTTP` method calls the `appHandler` function and displays the
returned error (if any) to the user.
@@ -255,9 +289,11 @@
function (instead of `HandleFunc`) as `appHandler` is an `http.Handler`
(not an `http.HandlerFunc`).
- func init() {
- http.Handle("/view", appHandler(viewRecord))
- }
+```go
+func init() {
+ http.Handle("/view", appHandler(viewRecord))
+}
+```
With this basic error handling infrastructure in place,
we can make it more user friendly.
@@ -267,15 +303,19 @@
To do this we create an `appError` struct containing an `error` and some other fields:
- type appError struct {
- Error error
- Message string
- Code int
- }
+```go
+type appError struct {
+ Error error
+ Message string
+ Code int
+}
+```
Next we modify the appHandler type to return `*appError` values:
- type appHandler func(http.ResponseWriter, *http.Request) *appError
+```go
+type appHandler func(http.ResponseWriter, *http.Request) *appError
+```
(It's usually a mistake to pass back the concrete type of an error rather than `error`,
for reasons discussed in [the Go FAQ](/doc/go_faq.html#nil_error),
@@ -286,29 +326,33 @@
to the user with the correct HTTP status `Code` and log the full `Error`
to the developer console:
- func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if e := fn(w, r); e != nil { // e is *appError, not os.Error.
- c := appengine.NewContext(r)
- c.Errorf("%v", e.Error)
- http.Error(w, e.Message, e.Code)
- }
- }
+```go
+func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if e := fn(w, r); e != nil { // e is *appError, not os.Error.
+ c := appengine.NewContext(r)
+ c.Errorf("%v", e.Error)
+ http.Error(w, e.Message, e.Code)
+ }
+}
+```
Finally, we update `viewRecord` to the new function signature and have it
return more context when it encounters an error:
- func viewRecord(w http.ResponseWriter, r *http.Request) *appError {
- c := appengine.NewContext(r)
- key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
- record := new(Record)
- if err := datastore.Get(c, key, record); err != nil {
- return &appError{err, "Record not found", 404}
- }
- if err := viewTemplate.Execute(w, record); err != nil {
- return &appError{err, "Can't display record", 500}
- }
- return nil
- }
+```go
+func viewRecord(w http.ResponseWriter, r *http.Request) *appError {
+ c := appengine.NewContext(r)
+ key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
+ record := new(Record)
+ if err := datastore.Get(c, key, record); err != nil {
+ return &appError{err, "Record not found", 404}
+ }
+ if err := viewTemplate.Execute(w, record); err != nil {
+ return &appError{err, "Can't display record", 500}
+ }
+ return nil
+}
+```
This version of `viewRecord` is the same length as the original,
but now each of those lines has specific meaning and we are providing a
diff --git a/_content/blog/error-syntax.md b/_content/blog/error-syntax.md
index 92f9554..4b97166 100644
--- a/_content/blog/error-syntax.md
+++ b/_content/blog/error-syntax.md
@@ -14,7 +14,7 @@
One of the oldest and most persistent complaints about Go concerns the verbosity of error handling.
We are all intimately (some may say painfully) familiar with this code pattern:
-```Go
+```go
x, err := call()
if err != nil {
// handle err
@@ -26,7 +26,7 @@
is rudimentary and they are simply returned.
Some programs end up with code that looks like this:
-```Go
+```go
func printSum(a, b string) error {
x, err := strconv.Atoi(a)
if err != nil {
@@ -63,7 +63,7 @@
If you're wondering if your particular error handling idea was previously considered,
read this document!
-```Go
+```go
// printSum implementation using the proposed check/handle mechanism.
func printSum(a, b string) error {
handle err { return err }
@@ -85,7 +85,7 @@
that rewrites existing error handling code using `try`.
The proposal was argued over intensively, approaching 900 comments on the [GitHub issue](/issue/32437).
-```Go
+```go
// printSum implementation using the proposed try mechanism.
func printSum(a, b string) error {
// use a defer statement to augment errors before returning
@@ -147,7 +147,7 @@
into code that uses the proposed new syntax, and we also prototyped the feature in the
compiler.
-```Go
+```go
// printSum implementation using the proposed "?" statements.
func printSum(a, b string) error {
x := strconv.Atoi(a) ?
@@ -234,7 +234,7 @@
error.
In this (admittedly contrived) example, the relative amount of boilerplate is much smaller:
- ```Go
+ ```go
func printSum(a, b string) error {
x, err := strconv.Atoi(a)
if err != nil {
@@ -255,7 +255,7 @@
For instance, in some cases [`cmp.Or`](/pkg/cmp#Or) may be used to deal with a
series of errors all at once:
- ```Go
+ ```go
func printSum(a, b string) error {
x, err1 := strconv.Atoi(a)
y, err2 := strconv.Atoi(b)
diff --git a/_content/blog/errors-are-values.md b/_content/blog/errors-are-values.md
index f6eb0f7..1638f2a 100644
--- a/_content/blog/errors-are-values.md
+++ b/_content/blog/errors-are-values.md
@@ -11,9 +11,11 @@
especially those new to the language, is how to handle errors.
The conversation often turns into a lament at the number of times the sequence
- if err != nil {
- return err
- }
+```go
+if err != nil {
+ return err
+}
+```
shows up.
We recently scanned all the open source projects we could find and
@@ -21,7 +23,9 @@
less often than some would have you believe.
Still, if the perception persists that one must type
- if err != nil
+```go
+if err != nil
+```
all the time, something must be wrong, and the obvious target is Go itself.
@@ -53,30 +57,36 @@
reports whether an error occurred.
Client code looks like this:
- scanner := bufio.NewScanner(input)
- for scanner.Scan() {
- token := scanner.Text()
- // process token
- }
- if err := scanner.Err(); err != nil {
- // process the error
- }
+```go
+scanner := bufio.NewScanner(input)
+for scanner.Scan() {
+ token := scanner.Text()
+ // process token
+}
+if err := scanner.Err(); err != nil {
+ // process the error
+}
+```
Sure, there is a nil check for an error, but it appears and executes only once.
The `Scan` method could instead have been defined as
- func (s *Scanner) Scan() (token []byte, error)
+```go
+func (s *Scanner) Scan() (token []byte, error)
+```
and then the example user code might be (depending on how the token is retrieved),
- scanner := bufio.NewScanner(input)
- for {
- token, err := scanner.Scan()
- if err != nil {
- return err // or maybe break
- }
- // process token
+```go
+scanner := bufio.NewScanner(input)
+for {
+ token, err := scanner.Scan()
+ if err != nil {
+ return err // or maybe break
}
+ // process token
+}
+```
This isn't very different, but there is one important distinction.
In this code, the client must check for an error on every iteration,
@@ -92,7 +102,9 @@
reports the error value when the client asks.
Trivial though this is, it's not the same as putting
- if err != nil
+```go
+if err != nil
+```
everywhere or asking the client to check for an error after every token.
It's programming with error values.
@@ -108,39 +120,43 @@
echoed the familiar lament about error checking.
He had some code that looked schematically like this:
- _, err = fd.Write(p0[a:b])
- if err != nil {
- return err
- }
- _, err = fd.Write(p1[c:d])
- if err != nil {
- return err
- }
- _, err = fd.Write(p2[e:f])
- if err != nil {
- return err
- }
- // and so on
+```go
+_, err = fd.Write(p0[a:b])
+if err != nil {
+ return err
+}
+_, err = fd.Write(p1[c:d])
+if err != nil {
+ return err
+}
+_, err = fd.Write(p2[e:f])
+if err != nil {
+ return err
+}
+// and so on
+```
It is very repetitive.
In the real code, which was longer,
there is more going on so it's not easy to just refactor this using a helper function,
but in this idealized form, a function literal closing over the error variable would help:
- var err error
- write := func(buf []byte) {
- if err != nil {
- return
- }
- _, err = w.Write(buf)
- }
- write(p0[a:b])
- write(p1[c:d])
- write(p2[e:f])
- // and so on
+```go
+var err error
+write := func(buf []byte) {
if err != nil {
- return err
+ return
}
+ _, err = w.Write(buf)
+}
+write(p0[a:b])
+write(p1[c:d])
+write(p2[e:f])
+// and so on
+if err != nil {
+ return err
+}
+```
This pattern works well, but requires a closure in each function doing the writes;
a separate helper function is clumsier to use because the `err` variable
@@ -154,10 +170,12 @@
I defined an object called an `errWriter`, something like this:
- type errWriter struct {
- w io.Writer
- err error
- }
+```go
+type errWriter struct {
+ w io.Writer
+ err error
+}
+```
and gave it one method, `write.`
It doesn't need to have the standard `Write` signature,
@@ -165,25 +183,29 @@
The `write` method calls the `Write` method of the underlying `Writer`
and records the first error for future reference:
- func (ew *errWriter) write(buf []byte) {
- if ew.err != nil {
- return
- }
- _, ew.err = ew.w.Write(buf)
+```go
+func (ew *errWriter) write(buf []byte) {
+ if ew.err != nil {
+ return
}
+ _, ew.err = ew.w.Write(buf)
+}
+```
As soon as an error occurs, the `write` method becomes a no-op but the error value is saved.
Given the `errWriter` type and its `write` method, the code above can be refactored:
- ew := &errWriter{w: fd}
- ew.write(p0[a:b])
- ew.write(p1[c:d])
- ew.write(p2[e:f])
- // and so on
- if ew.err != nil {
- return ew.err
- }
+```go
+ew := &errWriter{w: fd}
+ew.write(p0[a:b])
+ew.write(p1[c:d])
+ew.write(p2[e:f])
+// and so on
+if ew.err != nil {
+ return ew.err
+}
+```
This is cleaner, even compared to the use of a closure,
and also makes the actual sequence of writes being done easier to see on the page.
@@ -209,14 +231,16 @@
The `Write` method of `bufio.Writer` behaves just like our `errWriter.write`
method above, with `Flush` reporting the error, so our example could be written like this:
- b := bufio.NewWriter(fd)
- b.Write(p0[a:b])
- b.Write(p1[c:d])
- b.Write(p2[e:f])
- // and so on
- if b.Flush() != nil {
- return b.Flush()
- }
+```go
+b := bufio.NewWriter(fd)
+b.Write(p0[a:b])
+b.Write(p1[c:d])
+b.Write(p2[e:f])
+// and so on
+if b.Flush() != nil {
+ return b.Flush()
+}
+```
There is one significant drawback to this approach, at least for some applications:
there is no way to know how much of the processing completed before the error occurred.
diff --git a/_content/blog/examples.md b/_content/blog/examples.md
index 2d17743..cb225d7 100644
--- a/_content/blog/examples.md
+++ b/_content/blog/examples.md
@@ -41,18 +41,20 @@
is part of the [Go example repository](https://cs.opensource.google/go/x/example).
Here's an example that demonstrates its `String` function:
- package reverse_test
+```go
+package reverse_test
- import (
- "fmt"
+import (
+ "fmt"
- "golang.org/x/example/hello/reverse"
- )
+ "golang.org/x/example/hello/reverse"
+)
- func ExampleString() {
- fmt.Println(reverse.String("hello"))
- // Output: olleh
- }
+func ExampleString() {
+ fmt.Println(reverse.String("hello"))
+ // Output: olleh
+}
+```
This code might live in `example_test.go` in the `reverse` directory.
@@ -84,10 +86,12 @@
To see a failing example we can change the output comment text to something
obviously incorrect
- func ExampleString() {
- fmt.Println(reverse.String("hello"))
- // Output: golly
- }
+```go
+func ExampleString() {
+ fmt.Println(reverse.String("hello"))
+ // Output: golly
+}
+```
and run the tests again:
@@ -101,9 +105,11 @@
If we remove the output comment entirely
- func ExampleString() {
- fmt.Println(reverse.String("hello"))
- }
+```go
+func ExampleString() {
+ fmt.Println(reverse.String("hello"))
+}
+```
then the example function is compiled but not executed:
@@ -122,9 +128,11 @@
Godoc uses a naming convention to associate an example function with a
package-level identifier.
- func ExampleFoo() // documents the Foo function or type
- func ExampleBar_Qux() // documents the Qux method of type Bar
- func Example() // documents the package as a whole
+```go
+func ExampleFoo() // documents the Foo function or type
+func ExampleBar_Qux() // documents the Qux method of type Bar
+func Example() // documents the package as a whole
+```
Following this convention, godoc displays the `ExampleString` example
alongside the documentation for the `String` function.
@@ -133,9 +141,11 @@
beginning with an underscore followed by a lowercase letter.
Each of these examples documents the `String` function:
- func ExampleString()
- func ExampleString_second()
- func ExampleString_third()
+```go
+func ExampleString()
+func ExampleString_second()
+func ExampleString_third()
+```
## Larger examples
@@ -155,46 +165,48 @@
Here is a whole file example from the `sort` package:
{{raw `
- package sort_test
+~~~go
+package sort_test
- import (
- "fmt"
- "sort"
- )
+import (
+ "fmt"
+ "sort"
+)
- type Person struct {
- Name string
- Age int
+type Person struct {
+ Name string
+ Age int
+}
+
+func (p Person) String() string {
+ return fmt.Sprintf("%s: %d", p.Name, p.Age)
+}
+
+// ByAge implements sort.Interface for []Person based on
+// the Age field.
+type ByAge []Person
+
+func (a ByAge) Len() int { return len(a) }
+func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
+
+func Example() {
+ people := []Person{
+ {"Bob", 31},
+ {"John", 42},
+ {"Michael", 17},
+ {"Jenny", 26},
}
- func (p Person) String() string {
- return fmt.Sprintf("%s: %d", p.Name, p.Age)
- }
+ fmt.Println(people)
+ sort.Sort(ByAge(people))
+ fmt.Println(people)
- // ByAge implements sort.Interface for []Person based on
- // the Age field.
- type ByAge []Person
-
- func (a ByAge) Len() int { return len(a) }
- func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
- func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
-
- func Example() {
- people := []Person{
- {"Bob", 31},
- {"John", 42},
- {"Michael", 17},
- {"Jenny", 26},
- }
-
- fmt.Println(people)
- sort.Sort(ByAge(people))
- fmt.Println(people)
-
- // Output:
- // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
- // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
- }
+ // Output:
+ // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
+ // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
+}
+~~~
`}}
A package can contain multiple whole file examples; one example per file.
diff --git a/_content/blog/experiment.md b/_content/blog/experiment.md
index eab95e6..e589220 100644
--- a/_content/blog/experiment.md
+++ b/_content/blog/experiment.md
@@ -56,17 +56,19 @@
In the early days of Go, we quickly learned that
it was common to write code like this `addToList` function:
- func addToList(list []int, x int) []int {
- n := len(list)
- if n+1 > cap(list) {
- big := make([]int, n, (n+5)*2)
- copy(big, list)
- list = big
- }
- list = list[:n+1]
- list[n] = x
- return list
+```go
+func addToList(list []int, x int) []int {
+ n := len(list)
+ if n+1 > cap(list) {
+ big := make([]int, n, (n+5)*2)
+ copy(big, list)
+ list = big
}
+ list = list[:n+1]
+ list[n] = x
+ return list
+}
+```
We’d write the same code for slices of bytes,
and slices of strings, and so on.
@@ -116,13 +118,15 @@
We redefined append to allow appending from a string,
without adding anything new to the language.
- var b []byte
- var more []byte
- b = append(b, more...) // ok
+```go
+var b []byte
+var more []byte
+b = append(b, more...) // ok
- var b []byte
- var more string
- b = append(b, more...) // ok later
+var b []byte
+var more string
+b = append(b, more...) // ok later
+```
**Simplify by Removing**
@@ -143,8 +147,10 @@
the boolean forms of non-blocking channel operations from the language:
{{raw `
- ok := c <- x // before Go 1, was non-blocking send
- x, ok := <-c // before Go 1, was non-blocking receive
+~~~go
+ok := c <- x // before Go 1, was non-blocking send
+x, ok := <-c // before Go 1, was non-blocking receive
+~~~
`}}
These operations were also possible to do using `select`,
@@ -264,10 +270,12 @@
Error values had to start somewhere.
Here is the `Read` function from the first version of the `os` package:
- export func Read(fd int64, b *[]byte) (ret int64, errno int64) {
- r, e := syscall.read(fd, &b[0], int64(len(b)));
- return r, e
- }
+```go
+export func Read(fd int64, b *[]byte) (ret int64, errno int64) {
+ r, e := syscall.read(fd, &b[0], int64(len(b)));
+ return r, e
+}
+```
There was no `File` type yet, and also no error type.
`Read` and the other functions in the package
@@ -278,15 +286,17 @@
and code changed quickly.
Two hours and five minutes later, the API changed:
- export type Error struct { s string }
+```go
+export type Error struct { s string }
- func (e *Error) Print() { … } // to standard error!
- func (e *Error) String() string { … }
+func (e *Error) Print() { … } // to standard error!
+func (e *Error) String() string { … }
- export func Read(fd int64, b *[]byte) (ret int64, err *Error) {
- r, e := syscall.read(fd, &b[0], int64(len(b)));
- return r, ErrnoToError(e)
- }
+export func Read(fd int64, b *[]byte) (ret int64, err *Error) {
+ r, e := syscall.read(fd, &b[0], int64(len(b)));
+ return r, ErrnoToError(e)
+}
+```
This new API introduced the first `Error` type.
An error held a string and could return that string
@@ -335,15 +345,17 @@
a system call error number
and implements the `error` interface:
- package syscall
+```go
+package syscall
- type Errno int64
+type Errno int64
- func (e Errno) Error() string { ... }
+func (e Errno) Error() string { ... }
- const ECONNREFUSED = Errno(61)
+const ECONNREFUSED = Errno(61)
- ... err == ECONNREFUSED ...
+ ... err == ECONNREFUSED ...
+```
The `syscall` package also defines named constants
for the host operating system’s defined error numbers.
@@ -362,16 +374,18 @@
invoking a specific system call
with no additional information recorded:
- package os
+```go
+package os
- type SyscallError struct {
- Syscall string
- Err error
- }
+type SyscallError struct {
+ Syscall string
+ Err error
+}
- func (e *SyscallError) Error() string {
- return e.Syscall + ": " + e.Err.Error()
- }
+func (e *SyscallError) Error() string {
+ return e.Syscall + ": " + e.Err.Error()
+}
+```
Moving up another level,
in package `net`,
@@ -381,17 +395,19 @@
such as dial or listen,
and the network and addresses involved:
- package net
+```go
+package net
- type OpError struct {
- Op string
- Net string
- Source Addr
- Addr Addr
- Err error
- }
+type OpError struct {
+ Op string
+ Net string
+ Source Addr
+ Addr Addr
+ Err error
+}
- func (e *OpError) Error() string { ... }
+func (e *OpError) Error() string { ... }
+```
Putting these together,
the errors returned by operations like `net.Dial` can format as strings,
@@ -399,19 +415,21 @@
In this case, the error is a `net.OpError`, which adds context
to an `os.SyscallError`, which adds context to a `syscall.Errno`:
- c, err := net.Dial("tcp", "localhost:50001")
+```go
+c, err := net.Dial("tcp", "localhost:50001")
- // "dial tcp [::1]:50001: connect: connection refused"
+// "dial tcp [::1]:50001: connect: connection refused"
- err is &net.OpError{
- Op: "dial",
- Net: "tcp",
- Addr: &net.TCPAddr{IP: ParseIP("::1"), Port: 50001},
- Err: &os.SyscallError{
- Syscall: "connect",
- Err: syscall.Errno(61), // == ECONNREFUSED
- },
- }
+err is &net.OpError{
+ Op: "dial",
+ Net: "tcp",
+ Addr: &net.TCPAddr{IP: ParseIP("::1"), Port: 50001},
+ Err: &os.SyscallError{
+ Syscall: "connect",
+ Err: syscall.Errno(61), // == ECONNREFUSED
+ },
+}
+```
When we say errors are values, we mean both that
the entire Go language is available to define them
@@ -429,15 +447,17 @@
Here is the code:
- func spuriousENOTAVAIL(err error) bool {
- if op, ok := err.(*OpError); ok {
- err = op.Err
- }
- if sys, ok := err.(*os.SyscallError); ok {
- err = sys.Err
- }
- return err == syscall.EADDRNOTAVAIL
+```go
+func spuriousENOTAVAIL(err error) bool {
+ if op, ok := err.(*OpError); ok {
+ err = op.Err
}
+ if sys, ok := err.(*os.SyscallError); ok {
+ err = sys.Err
+ }
+ return err == syscall.EADDRNOTAVAIL
+}
+```
A [type assertion](/ref/spec#Type_assertions) peels away any `net.OpError` wrapping.
And then a second type assertion peels away any `os.SyscallError` wrapping.
@@ -494,24 +514,28 @@
either the error shouldn’t have an `Unwrap` method,
or the `Unwrap` method should return nil.
- // Go 1.13 optional method for error implementations.
+```go
+// Go 1.13 optional method for error implementations.
- interface {
- // Unwrap removes one layer of context,
- // returning the inner error if any, or else nil.
- Unwrap() error
- }
+interface {
+ // Unwrap removes one layer of context,
+ // returning the inner error if any, or else nil.
+ Unwrap() error
+}
+```
The way to call this optional method is to invoke the helper function `errors.Unwrap`,
which handles cases like the error itself being nil or not having an `Unwrap` method at all.
- package errors
+```go
+package errors
- // Unwrap returns the result of calling
- // the Unwrap method on err,
- // if err’s type defines an Unwrap method.
- // Otherwise, Unwrap returns nil.
- func Unwrap(err error) error
+// Unwrap returns the result of calling
+// the Unwrap method on err,
+// if err’s type defines an Unwrap method.
+// Otherwise, Unwrap returns nil.
+func Unwrap(err error) error
+```
We can use the `Unwrap` method
to write a simpler, more general version of `spuriousENOTAVAIL`.
@@ -520,23 +544,27 @@
the general version can loop, calling `Unwrap` to remove context,
until either it reaches `EADDRNOTAVAIL` or there’s no error left:
- func spuriousENOTAVAIL(err error) bool {
- for err != nil {
- if err == syscall.EADDRNOTAVAIL {
- return true
- }
- err = errors.Unwrap(err)
+```go
+func spuriousENOTAVAIL(err error) bool {
+ for err != nil {
+ if err == syscall.EADDRNOTAVAIL {
+ return true
}
- return false
+ err = errors.Unwrap(err)
}
+ return false
+}
+```
This loop is so common, though, that Go 1.13 defines a second function, `errors.Is`,
that repeatedly unwraps an error looking for a specific target.
So we can replace the entire loop with a single call to `errors.Is`:
- func spuriousENOTAVAIL(err error) bool {
- return errors.Is(err, syscall.EADDRNOTAVAIL)
- }
+```go
+func spuriousENOTAVAIL(err error) bool {
+ return errors.Is(err, syscall.EADDRNOTAVAIL)
+}
+```
At this point we probably wouldn’t even define the function;
it would be equally clear, and simpler, to call `errors.Is` directly at the call sites.
@@ -549,26 +577,30 @@
`errors.Is` is the wrapper-aware
version of an error equality check:
- err == target
+```go
+err == target
- →
+ →
- errors.Is(err, target)
+errors.Is(err, target)
+```
And `errors.As` is the wrapper-aware
version of an error type assertion:
- target, ok := err.(*Type)
- if ok {
- ...
- }
+```go
+target, ok := err.(*Type)
+if ok {
+ ...
+}
- →
+ →
- var target *Type
- if errors.As(err, &target) {
- ...
- }
+var target *Type
+if errors.As(err, &target) {
+ ...
+}
+```
**To Unwrap Or Not To Unwrap?**
@@ -584,9 +616,11 @@
That is, the result of `fmt.Errorf` has not been possible to unwrap.
Consider this example:
- // errors.Unwrap(err2) == nil
- // err1 is not available (same as earlier Go versions)
- err2 := fmt.Errorf("connect: %v", err1)
+```go
+// errors.Unwrap(err2) == nil
+// err1 is not available (same as earlier Go versions)
+err2 := fmt.Errorf("connect: %v", err1)
+```
If `err2` is returned to
a caller, that caller has never had any way to open up `err2` and access `err1`.
@@ -598,9 +632,11 @@
and makes the resulting error’s `Unwrap` method return that argument.
In our example, suppose we replace `%v` with `%w`:
- // errors.Unwrap(err4) == err3
- // (%w is new in Go 1.13)
- err4 := fmt.Errorf("connect: %w", err3)
+```go
+// errors.Unwrap(err4) == err3
+// (%w is new in Go 1.13)
+err4 := fmt.Errorf("connect: %w", err3)
+```
Now, if `err4` is returned to a caller,
the caller can use `Unwrap` to retrieve `err3`.
@@ -627,17 +663,19 @@
including stack frame information
and support for localized, translated errors.
- // Optional method for error implementations
- type Formatter interface {
- Format(p Printer) (next error)
- }
+```go
+// Optional method for error implementations
+type Formatter interface {
+ Format(p Printer) (next error)
+}
- // Interface passed to Format
- type Printer interface {
- Print(args ...interface{})
- Printf(format string, args ...interface{})
- Detail() bool
- }
+// Interface passed to Format
+type Printer interface {
+ Print(args ...interface{})
+ Printf(format string, args ...interface{})
+ Detail() bool
+}
+```
This one is not as simple as `Unwrap`,
and I won’t go into the details here.
@@ -660,21 +698,23 @@
[`compress/lzw/writer.go`](https://go.googlesource.com/go/+/go1.12/src/compress/lzw/writer.go#209) in the standard library:
{{raw `
- // Write the savedCode if valid.
- if e.savedCode != invalidCode {
- if err := e.write(e, e.savedCode); err != nil {
- return err
- }
- if err := e.incHi(); err != nil && err != errOutOfCodes {
- return err
- }
- }
-
- // Write the eof code.
- eof := uint32(1)<<e.litWidth + 1
- if err := e.write(e, eof); err != nil {
+~~~go
+// Write the savedCode if valid.
+if e.savedCode != invalidCode {
+ if err := e.write(e, e.savedCode); err != nil {
return err
}
+ if err := e.incHi(); err != nil && err != errOutOfCodes {
+ return err
+ }
+}
+
+// Write the eof code.
+eof := uint32(1)<<e.litWidth + 1
+if err := e.write(e, eof); err != nil {
+ return err
+}
+~~~
`}}
At a glance, this code is about half error checks.
@@ -694,17 +734,19 @@
from the call. We can use `check` to simplify the lzw code:
{{raw `
- // Write the savedCode if valid.
- if e.savedCode != invalidCode {
- check e.write(e, e.savedCode)
- if err := e.incHi(); err != errOutOfCodes {
- check err
- }
+~~~go
+// Write the savedCode if valid.
+if e.savedCode != invalidCode {
+ check e.write(e, e.savedCode)
+ if err := e.incHi(); err != errOutOfCodes {
+ check err
}
+}
- // Write the eof code.
- eof := uint32(1)<<e.litWidth + 1
- check e.write(e, eof)
+// Write the eof code.
+eof := uint32(1)<<e.litWidth + 1
+check e.write(e, eof)
+~~~
`}}
This version of the same code uses `check`,
@@ -719,21 +761,23 @@
like in this snippet:
{{raw `
- handle err {
- err = fmt.Errorf("closing writer: %w", err)
- }
+~~~go
+handle err {
+ err = fmt.Errorf("closing writer: %w", err)
+}
- // Write the savedCode if valid.
- if e.savedCode != invalidCode {
- check e.write(e, e.savedCode)
- if err := e.incHi(); err != errOutOfCodes {
- check err
- }
+// Write the savedCode if valid.
+if e.savedCode != invalidCode {
+ check e.write(e, e.savedCode)
+ if err := e.incHi(); err != errOutOfCodes {
+ check err
}
+}
- // Write the eof code.
- eof := uint32(1)<<e.litWidth + 1
- check e.write(e, eof)
+// Write the eof code.
+eof := uint32(1)<<e.litWidth + 1
+check e.write(e, eof)
+~~~
`}}
In essence, `check` was a short way to write the `if` statement,
@@ -758,19 +802,21 @@
Now the same code would look like this:
{{raw `
- defer errd.Wrapf(&err, "closing writer")
+~~~go
+defer errd.Wrapf(&err, "closing writer")
- // Write the savedCode if valid.
- if e.savedCode != invalidCode {
- try(e.write(e, e.savedCode))
- if err := e.incHi(); err != errOutOfCodes {
- try(err)
- }
+// Write the savedCode if valid.
+if e.savedCode != invalidCode {
+ try(e.write(e, e.savedCode))
+ if err := e.incHi(); err != errOutOfCodes {
+ try(err)
}
+}
- // Write the eof code.
- eof := uint32(1)<<e.litWidth + 1
- try(e.write(e, eof))
+// Write the eof code.
+eof := uint32(1)<<e.litWidth + 1
+try(e.write(e, eof))
+~~~
`}}
We spent most of June discussing this proposal publicly on GitHub.
@@ -809,20 +855,22 @@
For example, here is a generic channel filter:
{{raw `
- // Filter copies values from c to the returned channel,
- // passing along only those values satisfying f.
- func Filter(type value)(f func(value) bool, c <-chan value) <-chan value {
- out := make(chan value)
- go func() {
- for v := range c {
- if f(v) {
- out <- v
- }
+~~~go
+// Filter copies values from c to the returned channel,
+// passing along only those values satisfying f.
+func Filter(type value)(f func(value) bool, c <-chan value) <-chan value {
+ out := make(chan value)
+ go func() {
+ for v := range c {
+ if f(v) {
+ out <- v
}
- close(out)
- }()
- return out
- }
+ }
+ close(out)
+ }()
+ return out
+}
+~~~
`}}
We’ve been thinking about generics since work on Go began,
diff --git a/_content/blog/external-libraries.md b/_content/blog/external-libraries.md
index 8001db2..15f007d 100644
--- a/_content/blog/external-libraries.md
+++ b/_content/blog/external-libraries.md
@@ -65,12 +65,14 @@
Once goinstalled, the packages can be imported using those same paths:
- import (
- "launchpad.net/mgo"
- "github.com/dchest/authcookie"
- "go-charset.googlecode.com/hg/charset"
- "github.com/madari/go-socket.io"
- )
+```go
+import (
+ "launchpad.net/mgo"
+ "github.com/dchest/authcookie"
+ "go-charset.googlecode.com/hg/charset"
+ "github.com/madari/go-socket.io"
+)
+```
Also, as they are now a part of the local Go system,
we can inspect their documentation with [godoc](/cmd/godoc/):
diff --git a/_content/blog/first-go-program.md b/_content/blog/first-go-program.md
index 4b000b7..3f3c35e 100644
--- a/_content/blog/first-go-program.md
+++ b/_content/blog/first-go-program.md
@@ -72,7 +72,9 @@
`c` and returns a boolean.
{{raw `
- function WhiteSpace(bool <- c int)
+~~~go
+function WhiteSpace(bool <- c int)
+~~~
`}}
This arrow was a stop-gap measure until a better syntax arose for declaring
@@ -81,18 +83,22 @@
Methods were distinct from functions and had their own keyword.
{{raw `
- method (this *Slist) Car(*Slist <-) {
- return this.list.car;
- }
+~~~go
+method (this *Slist) Car(*Slist <-) {
+ return this.list.car;
+}
+~~~
`}}
And methods were pre-declared in the struct definition, although that changed soon.
{{raw `
- type Slist struct {
- ...
- Car method(*Slist <-);
- }
+~~~go
+type Slist struct {
+ ...
+ Car method(*Slist <-);
+}
+~~~
`}}
There were no strings, although they were in the spec.
@@ -101,18 +107,22 @@
yet, let alone implemented, although there was the unimplemented concept of an
"open array".)
- input[i] = '('; i = i + 1;
- input[i] = 'd'; i = i + 1;
- input[i] = 'e'; i = i + 1;
- input[i] = 'f'; i = i + 1;
- input[i] = 'n'; i = i + 1;
- input[i] = ' '; i = i + 1;
- ...
+```go
+input[i] = '('; i = i + 1;
+input[i] = 'd'; i = i + 1;
+input[i] = 'e'; i = i + 1;
+input[i] = 'f'; i = i + 1;
+input[i] = 'n'; i = i + 1;
+input[i] = ' '; i = i + 1;
+...
+```
Both `panic` and `print` were built-in keywords, not pre-declared functions.
- print "parse error: expected ", c, "\n";
- panic "parse";
+```go
+print "parse error: expected ", c, "\n";
+panic "parse";
+```
And there are many other little differences; see if you can identify some others.
diff --git a/_content/blog/flight-recorder.md b/_content/blog/flight-recorder.md
index 13ead77..b1ded12 100644
--- a/_content/blog/flight-recorder.md
+++ b/_content/blog/flight-recorder.md
@@ -69,76 +69,78 @@
minute, sends a report of all the guessed numbers to another service via an HTTP request.
{{raw `
- // bucket is a simple mutex-protected counter.
- type bucket struct {
- mu sync.Mutex
- guesses int
- }
+~~~go
+// bucket is a simple mutex-protected counter.
+type bucket struct {
+ mu sync.Mutex
+ guesses int
+}
- func main() {
- // Make one bucket for each valid number a client could guess.
- // The HTTP handler will look up the guessed number in buckets by
- // using the number as an index into the slice.
- buckets := make([]bucket, 100)
+func main() {
+ // Make one bucket for each valid number a client could guess.
+ // The HTTP handler will look up the guessed number in buckets by
+ // using the number as an index into the slice.
+ buckets := make([]bucket, 100)
- // Every minute, we send a report of how many times each number was guessed.
- go func() {
- for range time.Tick(1 * time.Minute) {
- sendReport(buckets)
- }
- }()
-
- // Choose the number to be guessed.
- answer := rand.Intn(len(buckets))
-
- http.HandleFunc("/guess-number", func(w http.ResponseWriter, r *http.Request) {
- start := time.Now()
-
- // Fetch the number from the URL query variable "guess" and convert it
- // to an integer. Then, validate it.
- guess, err := strconv.Atoi(r.URL.Query().Get("guess"))
- if err != nil || !(0 <= guess && guess < len(buckets)) {
- http.Error(w, "invalid 'guess' value", http.StatusBadRequest)
- return
- }
-
- // Select the appropriate bucket and safely increment its value.
- b := &buckets[guess]
- b.mu.Lock()
- b.guesses++
- b.mu.Unlock()
-
- // Respond to the client with the guess and whether it was correct.
- fmt.Fprintf(w, "guess: %d, correct: %t", guess, guess == answer)
-
- log.Printf("HTTP request: endpoint=/guess-number guess=%d duration=%s", guess, time.Since(start))
- })
- log.Fatal(http.ListenAndServe(":8090", nil))
- }
-
- // sendReport posts the current state of buckets to a remote service.
- func sendReport(buckets []bucket) {
- counts := make([]int, len(buckets))
-
- for index := range buckets {
- b := &buckets[index]
- b.mu.Lock()
- defer b.mu.Unlock()
-
- counts[index] = b.guesses
+ // Every minute, we send a report of how many times each number was guessed.
+ go func() {
+ for range time.Tick(1 * time.Minute) {
+ sendReport(buckets)
}
+ }()
- // Marshal the report data into a JSON payload.
- b, err := json.Marshal(counts)
- if err != nil {
- log.Printf("failed to marshal report data: error=%s", err)
+ // Choose the number to be guessed.
+ answer := rand.Intn(len(buckets))
+
+ http.HandleFunc("/guess-number", func(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+
+ // Fetch the number from the URL query variable "guess" and convert it
+ // to an integer. Then, validate it.
+ guess, err := strconv.Atoi(r.URL.Query().Get("guess"))
+ if err != nil || !(0 <= guess && guess < len(buckets)) {
+ http.Error(w, "invalid 'guess' value", http.StatusBadRequest)
return
}
- url := "http://localhost:8091/guess-number-report"
- if _, err := http.Post(url, "application/json", bytes.NewReader(b)); err != nil {
- log.Printf("failed to send report: %s", err)
- }
+
+ // Select the appropriate bucket and safely increment its value.
+ b := &buckets[guess]
+ b.mu.Lock()
+ b.guesses++
+ b.mu.Unlock()
+
+ // Respond to the client with the guess and whether it was correct.
+ fmt.Fprintf(w, "guess: %d, correct: %t", guess, guess == answer)
+
+ log.Printf("HTTP request: endpoint=/guess-number guess=%d duration=%s", guess, time.Since(start))
+ })
+ log.Fatal(http.ListenAndServe(":8090", nil))
+}
+
+// sendReport posts the current state of buckets to a remote service.
+func sendReport(buckets []bucket) {
+ counts := make([]int, len(buckets))
+
+ for index := range buckets {
+ b := &buckets[index]
+ b.mu.Lock()
+ defer b.mu.Unlock()
+
+ counts[index] = b.guesses
}
+
+ // Marshal the report data into a JSON payload.
+ b, err := json.Marshal(counts)
+ if err != nil {
+ log.Printf("failed to marshal report data: error=%s", err)
+ return
+ }
+ url := "http://localhost:8091/guess-number-report"
+ if _, err := http.Post(url, "application/json", bytes.NewReader(b)); err != nil {
+ log.Printf("failed to send report: %s", err)
+ }
+}
+~~~
`}}
Here is the full code for the server:
@@ -171,12 +173,14 @@
First, in `main`, we'll configure and start the flight recorder:
{{raw `
- // Set up the flight recorder
- fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{
- MinAge: 200 * time.Millisecond,
- MaxBytes: 1 << 20, // 1 MiB
- })
- fr.Start()
+~~~go
+// Set up the flight recorder
+fr := trace.NewFlightRecorder(trace.FlightRecorderConfig{
+ MinAge: 200 * time.Millisecond,
+ MaxBytes: 1 << 20, // 1 MiB
+})
+fr.Start()
+~~~
`}}
`MinAge` configures the duration for which trace data is reliably retained, and we
@@ -189,31 +193,33 @@
Next, we'll add a helper function to capture the snapshot and write it to a file:
{{raw `
- var once sync.Once
+~~~go
+var once sync.Once
- // captureSnapshot captures a flight recorder snapshot.
- func captureSnapshot(fr *trace.FlightRecorder) {
- // once.Do ensures that the provided function is executed only once.
- once.Do(func() {
- f, err := os.Create("snapshot.trace")
- if err != nil {
- log.Printf("opening snapshot file %s failed: %s", f.Name(), err)
- return
- }
- defer f.Close() // ignore error
+// captureSnapshot captures a flight recorder snapshot.
+func captureSnapshot(fr *trace.FlightRecorder) {
+ // once.Do ensures that the provided function is executed only once.
+ once.Do(func() {
+ f, err := os.Create("snapshot.trace")
+ if err != nil {
+ log.Printf("opening snapshot file %s failed: %s", f.Name(), err)
+ return
+ }
+ defer f.Close() // ignore error
- // WriteTo writes the flight recorder data to the provided io.Writer.
- _, err = fr.WriteTo(f)
- if err != nil {
- log.Printf("writing snapshot to file %s failed: %s", f.Name(), err)
- return
- }
+ // WriteTo writes the flight recorder data to the provided io.Writer.
+ _, err = fr.WriteTo(f)
+ if err != nil {
+ log.Printf("writing snapshot to file %s failed: %s", f.Name(), err)
+ return
+ }
- // Stop the flight recorder after the snapshot has been taken.
- fr.Stop()
- log.Printf("captured a flight recorder snapshot to %s", f.Name())
- })
- }
+ // Stop the flight recorder after the snapshot has been taken.
+ fr.Stop()
+ log.Printf("captured a flight recorder snapshot to %s", f.Name())
+ })
+}
+~~~
`}}
And finally, just before logging a completed request, we'll trigger the snapshot if the request
diff --git a/_content/blog/fuzz-beta.md b/_content/blog/fuzz-beta.md
index 3e4895a..2f81b12 100644
--- a/_content/blog/fuzz-beta.md
+++ b/_content/blog/fuzz-beta.md
@@ -47,34 +47,36 @@
Below is an example of a fuzz test that’s testing the behavior of the [net/url
package](https://pkg.go.dev/net/url#ParseQuery).
- //go:build go1.18
- // +build go1.18
+```go
+//go:build go1.18
+// +build go1.18
- package fuzz
+package fuzz
- import (
- "net/url"
- "reflect"
- "testing"
- )
+import (
+ "net/url"
+ "reflect"
+ "testing"
+)
- func FuzzParseQuery(f *testing.F) {
- f.Add("x=1&y=2")
- f.Fuzz(func(t *testing.T, queryStr string) {
- query, err := url.ParseQuery(queryStr)
- if err != nil {
- t.Skip()
- }
- queryStr2 := query.Encode()
- query2, err := url.ParseQuery(queryStr2)
- if err != nil {
- t.Fatalf("ParseQuery failed to decode a valid encoded query %s: %v", queryStr2, err)
- }
- if !reflect.DeepEqual(query, query2) {
- t.Errorf("ParseQuery gave different query after being encoded\nbefore: %v\nafter: %v", query, query2)
- }
- })
- }
+func FuzzParseQuery(f *testing.F) {
+ f.Add("x=1&y=2")
+ f.Fuzz(func(t *testing.T, queryStr string) {
+ query, err := url.ParseQuery(queryStr)
+ if err != nil {
+ t.Skip()
+ }
+ queryStr2 := query.Encode()
+ query2, err := url.ParseQuery(queryStr2)
+ if err != nil {
+ t.Fatalf("ParseQuery failed to decode a valid encoded query %s: %v", queryStr2, err)
+ }
+ if !reflect.DeepEqual(query, query2) {
+ t.Errorf("ParseQuery gave different query after being encoded\nbefore: %v\nafter: %v", query, query2)
+ }
+ })
+}
+```
You can read more about fuzzing at pkg.go.dev, including [an overview
of fuzzing with Go](https://pkg.go.dev/testing@master#hdr-Fuzzing) and the
diff --git a/_content/blog/generate.md b/_content/blog/generate.md
index ddc274d..6b600c5 100644
--- a/_content/blog/generate.md
+++ b/_content/blog/generate.md
@@ -61,7 +61,9 @@
To have `go` `generate` drive the process, in any one of the regular (non-generated) `.go` files
in the same directory, add this comment anywhere in the file:
- //go:generate goyacc -o gopher.go -p parser gopher.y
+```go
+//go:generate goyacc -o gopher.go -p parser gopher.y
+```
This text is just the command above prefixed by a special comment recognized by `go` `generate`.
The comment must start at the beginning of the line and have no spaces between the `//` and the `go:generate`.
@@ -102,37 +104,43 @@
[`stringer`](https://godoc.org/golang.org/x/tools/cmd/stringer).
Imagine we have some code that contains a set of integer constants defining different types of pills:
- package painkiller
+```go
+package painkiller
- type Pill int
+type Pill int
- const (
- Placebo Pill = iota
- Aspirin
- Ibuprofen
- Paracetamol
- Acetaminophen = Paracetamol
- )
+const (
+ Placebo Pill = iota
+ Aspirin
+ Ibuprofen
+ Paracetamol
+ Acetaminophen = Paracetamol
+)
+```
For debugging, we'd like these constants to pretty-print themselves, which means we want a method with signature,
- func (p Pill) String() string
+```go
+func (p Pill) String() string
+```
It's easy to write one by hand, perhaps like this:
- func (p Pill) String() string {
- switch p {
- case Placebo:
- return "Placebo"
- case Aspirin:
- return "Aspirin"
- case Ibuprofen:
- return "Ibuprofen"
- case Paracetamol: // == Acetaminophen
- return "Paracetamol"
- }
- return fmt.Sprintf("Pill(%d)", p)
+```go
+func (p Pill) String() string {
+ switch p {
+ case Placebo:
+ return "Placebo"
+ case Aspirin:
+ return "Aspirin"
+ case Ibuprofen:
+ return "Ibuprofen"
+ case Paracetamol: // == Acetaminophen
+ return "Paracetamol"
}
+ return fmt.Sprintf("Pill(%d)", p)
+}
+```
There are other ways to write this function, of course.
We could use a slice of strings indexed by Pill, or a map, or some other technique.
@@ -145,7 +153,9 @@
Although it can be run in isolation, it is intended to be driven by `go` `generate`.
To use it, add a generate comment to the source, perhaps near the type definition:
- //go:generate stringer -type=Pill
+```go
+//go:generate stringer -type=Pill
+```
This rule specifies that `go` `generate` should run the `stringer` tool to generate a `String` method for type `Pill`.
The output is automatically written to `pill_string.go` (a default we could override with the
@@ -198,24 +208,26 @@
For instance, if the constants are sparse, it might use a map.
Here's a trivial example based on a constant set representing powers of two:
- const _Power_name = "p0p1p2p3p4p5..."
+```go
+const _Power_name = "p0p1p2p3p4p5..."
- var _Power_map = map[Power]string{
- 1: _Power_name[0:2],
- 2: _Power_name[2:4],
- 4: _Power_name[4:6],
- 8: _Power_name[6:8],
- 16: _Power_name[8:10],
- 32: _Power_name[10:12],
- ...,
- }
+var _Power_map = map[Power]string{
+ 1: _Power_name[0:2],
+ 2: _Power_name[2:4],
+ 4: _Power_name[4:6],
+ 8: _Power_name[6:8],
+ 16: _Power_name[8:10],
+ 32: _Power_name[10:12],
+ ...,
+}
- func (i Power) String() string {
- if str, ok := _Power_map[i]; ok {
- return str
- }
- return fmt.Sprintf("Power(%d)", i)
+func (i Power) String() string {
+ if str, ok := _Power_map[i]; ok {
+ return str
}
+ return fmt.Sprintf("Power(%d)", i)
+}
+```
In short, generating the method automatically allows us to do a better job than we would expect a human to do.
diff --git a/_content/blog/generic-interfaces.md b/_content/blog/generic-interfaces.md
index 32a1e58..b4cc8f4 100644
--- a/_content/blog/generic-interfaces.md
+++ b/_content/blog/generic-interfaces.md
@@ -23,33 +23,35 @@
It restricts a type parameter to ordered types (strings and numbers) and allows methods of the type to use the built-in ordering operators.
{{raw `
- // The zero value of a Tree is a ready-to-use empty tree.
- type Tree[E cmp.Ordered] struct {
- root *node[E]
- }
+~~~go
+// The zero value of a Tree is a ready-to-use empty tree.
+type Tree[E cmp.Ordered] struct {
+ root *node[E]
+}
- func (t *Tree[E]) Insert(element E) {
- t.root = t.root.insert(element)
- }
+func (t *Tree[E]) Insert(element E) {
+ t.root = t.root.insert(element)
+}
- type node[E cmp.Ordered] struct {
- value E
- left *node[E]
- right *node[E]
- }
+type node[E cmp.Ordered] struct {
+ value E
+ left *node[E]
+ right *node[E]
+}
- func (n *node[E]) insert(element E) *node[E] {
- if n == nil {
- return &node[E]{value: element}
- }
- switch {
- case element < n.value:
- n.left = n.left.insert(element)
- case element > n.value:
- n.right = n.right.insert(element)
- }
- return n
+func (n *node[E]) insert(element E) *node[E] {
+ if n == nil {
+ return &node[E]{value: element}
}
+ switch {
+ case element < n.value:
+ n.left = n.left.insert(element)
+ case element > n.value:
+ n.right = n.right.insert(element)
+ }
+ return n
+}
+~~~
`}}
([playground](/play/p/H7-n33X7P2h))
@@ -60,39 +62,41 @@
We can remedy that by requiring the user to provide a comparison function:
{{raw `
- // A FuncTree must be created with NewFuncTree.
- type FuncTree[E any] struct {
- root *funcNode[E]
- cmp func(E, E) int
- }
+~~~go
+// A FuncTree must be created with NewFuncTree.
+type FuncTree[E any] struct {
+ root *funcNode[E]
+ cmp func(E, E) int
+}
- func NewFuncTree[E any](cmp func(E, E) int) *FuncTree[E] {
- return &FuncTree[E]{cmp: cmp}
- }
+func NewFuncTree[E any](cmp func(E, E) int) *FuncTree[E] {
+ return &FuncTree[E]{cmp: cmp}
+}
- func (t *FuncTree[E]) Insert(element E) {
- t.root = t.root.insert(t.cmp, element)
- }
+func (t *FuncTree[E]) Insert(element E) {
+ t.root = t.root.insert(t.cmp, element)
+}
- type funcNode[E any] struct {
- value E
- left *funcNode[E]
- right *funcNode[E]
- }
+type funcNode[E any] struct {
+ value E
+ left *funcNode[E]
+ right *funcNode[E]
+}
- func (n *funcNode[E]) insert(cmp func(E, E) int, element E) *funcNode[E] {
- if n == nil {
- return &funcNode[E]{value: element}
- }
- sign := cmp(element, n.value)
- switch {
- case sign < 0:
- n.left = n.left.insert(cmp, element)
- case sign > 0:
- n.right = n.right.insert(cmp, element)
- }
- return n
+func (n *funcNode[E]) insert(cmp func(E, E) int, element E) *funcNode[E] {
+ if n == nil {
+ return &funcNode[E]{value: element}
}
+ sign := cmp(element, n.value)
+ switch {
+ case sign < 0:
+ n.left = n.left.insert(cmp, element)
+ case sign > 0:
+ n.right = n.right.insert(cmp, element)
+ }
+ return n
+}
+~~~
`}}
([playground](/play/p/tiEjuxCHtFF))
@@ -110,9 +114,11 @@
The first approach we might try is to define a plain old interface with a `Compare` method:
{{raw `
- type Comparer interface {
- Compare(Comparer) int
- }
+~~~go
+type Comparer interface {
+ Compare(Comparer) int
+}
+~~~
`}}
However, we quickly realize that this does not work well.
@@ -123,9 +129,11 @@
A better approach is to make the `Comparer` interface itself generic:
{{raw `
- type Comparer[T any] interface {
- Compare(T) int
- }
+~~~go
+type Comparer[T any] interface {
+ Compare(T) int
+}
+~~~
`}}
This `Comparer` now describes a whole family of interfaces, one for each type that `Comparer` may be instantiated with.
@@ -133,8 +141,10 @@
For instance, `time.Time` naturally implements `Comparer[time.Time]` because [it has a matching `Compare` method](/pkg/time#Time.Compare):
{{raw `
- // Implements Comparer[Time]
- func (t Time) Compare(u Time) int
+~~~go
+// Implements Comparer[Time]
+func (t Time) Compare(u Time) int
+~~~
`}}
This is better, but not enough.
@@ -143,34 +153,36 @@
Instead, it is a consequence of how we use `Comparer` as a constraint for the type parameter of `MethodTree`:
{{raw `
- // The zero value of a MethodTree is a ready-to-use empty tree.
- type MethodTree[E Comparer[E]] struct {
- root *methodNode[E]
- }
+~~~go
+// The zero value of a MethodTree is a ready-to-use empty tree.
+type MethodTree[E Comparer[E]] struct {
+ root *methodNode[E]
+}
- func (t *MethodTree[E]) Insert(element E) {
- t.root = t.root.insert(element)
- }
+func (t *MethodTree[E]) Insert(element E) {
+ t.root = t.root.insert(element)
+}
- type methodNode[E Comparer[E]] struct {
- value E
- left *methodNode[E]
- right *methodNode[E]
- }
+type methodNode[E Comparer[E]] struct {
+ value E
+ left *methodNode[E]
+ right *methodNode[E]
+}
- func (n *methodNode[E]) insert(element E) *methodNode[E] {
- if n == nil {
- return &methodNode[E]{value: element}
- }
- sign := element.Compare(n.value)
- switch {
- case sign < 0:
- n.left = n.left.insert(element)
- case sign > 0:
- n.right = n.right.insert(element)
- }
- return n
+func (n *methodNode[E]) insert(element E) *methodNode[E] {
+ if n == nil {
+ return &methodNode[E]{value: element}
}
+ sign := element.Compare(n.value)
+ switch {
+ case sign < 0:
+ n.left = n.left.insert(element)
+ case sign > 0:
+ n.right = n.right.insert(element)
+ }
+ return n
+}
+~~~
`}}
([playground](/play/p/LuhzYej_2SP))
@@ -178,8 +190,10 @@
Because `time.Time` implements `Comparer[time.Time]` it is now a valid type argument for this container, and we can still use the zero value as an empty container:
{{raw `
- var t MethodTree[time.Time]
- t.Insert(time.Now())
+~~~go
+var t MethodTree[time.Time]
+t.Insert(time.Now())
+~~~
`}}
For full flexibility, a library can provide all three API versions.
@@ -187,40 +201,42 @@
We could use the function version for that, as it is the most general:
{{raw `
- type node[E any] struct {
- value E
- left *node[E]
- right *node[E]
- }
+~~~go
+type node[E any] struct {
+ value E
+ left *node[E]
+ right *node[E]
+}
- func (n *node[E]) insert(cmp func(E, E) int, element E) *node[E] {
- if n == nil {
- return &node[E]{value: element}
- }
- sign := cmp(element, n.value)
- switch {
- case sign < 0:
- n.left = n.left.insert(cmp, element)
- case sign > 0:
- n.right = n.right.insert(cmp, element)
- }
- return n
+func (n *node[E]) insert(cmp func(E, E) int, element E) *node[E] {
+ if n == nil {
+ return &node[E]{value: element}
}
+ sign := cmp(element, n.value)
+ switch {
+ case sign < 0:
+ n.left = n.left.insert(cmp, element)
+ case sign > 0:
+ n.right = n.right.insert(cmp, element)
+ }
+ return n
+}
- // Insert inserts element into the tree, if E implements cmp.Ordered.
- func (t *Tree[E]) Insert(element E) {
- t.root = t.root.insert(cmp.Compare[E], element)
- }
+// Insert inserts element into the tree, if E implements cmp.Ordered.
+func (t *Tree[E]) Insert(element E) {
+ t.root = t.root.insert(cmp.Compare[E], element)
+}
- // Insert inserts element into the tree, using the provided comparison function.
- func (t *FuncTree[E]) Insert(element E) {
- t.root = t.root.insert(t.cmp, element)
- }
+// Insert inserts element into the tree, using the provided comparison function.
+func (t *FuncTree[E]) Insert(element E) {
+ t.root = t.root.insert(t.cmp, element)
+}
- // Insert inserts element into the tree, if E implements Comparer[E].
- func (t *MethodTree[E]) Insert(element E) {
- t.root = t.root.insert(E.Compare, element)
- }
+// Insert inserts element into the tree, if E implements Comparer[E].
+func (t *MethodTree[E]) Insert(element E) {
+ t.root = t.root.insert(E.Compare, element)
+}
+~~~
`}}
([playground](/play/p/jzmoaH5eaIv))
@@ -241,35 +257,37 @@
{{raw `
- type OrderedSet[E Comparer[E]] struct {
- tree MethodTree[E] // for efficient iteration in order
- elements map[E]bool // for (near) constant time lookup
- }
+~~~go
+type OrderedSet[E Comparer[E]] struct {
+ tree MethodTree[E] // for efficient iteration in order
+ elements map[E]bool // for (near) constant time lookup
+}
- func (s *OrderedSet[E]) Has(e E) bool {
- return s.elements[e]
- }
+func (s *OrderedSet[E]) Has(e E) bool {
+ return s.elements[e]
+}
- func (s *OrderedSet[E]) Insert(e E) {
- if s.elements == nil {
- s.elements = make(map[E]bool)
- }
- if s.elements[e] {
- return
- }
- s.elements[e] = true
- s.tree.Insert(e)
+func (s *OrderedSet[E]) Insert(e E) {
+ if s.elements == nil {
+ s.elements = make(map[E]bool)
}
+ if s.elements[e] {
+ return
+ }
+ s.elements[e] = true
+ s.tree.Insert(e)
+}
- func (s *OrderedSet[E]) All() iter.Seq[E] {
- return func(yield func(E) bool) {
- s.tree.root.all(yield)
- }
+func (s *OrderedSet[E]) All() iter.Seq[E] {
+ return func(yield func(E) bool) {
+ s.tree.root.all(yield)
}
+}
- func (n *node[E]) all(yield func(E) bool) bool {
- return n == nil || (n.left.all(yield) && yield(n.value) && n.right.all(yield))
- }
+func (n *node[E]) all(yield func(E) bool) bool {
+ return n == nil || (n.left.all(yield) && yield(n.value) && n.right.all(yield))
+}
+~~~
`}}
([playground](/play/p/TANUnnSnDqf))
@@ -287,10 +305,12 @@
1. We can [embed](/ref/spec#Embedded_interfaces) `comparable` into our original `Comparer` definition ([playground](/play/p/g8NLjZCq97q)):
{{raw `
- type Comparer[E any] interface {
- comparable
- Compare(E) int
- }
+ ~~~go
+ type Comparer[E any] interface {
+ comparable
+ Compare(E) int
+ }
+ ~~~
`}}
This has the downside that it would also make our `Tree` types only usable with types that are `comparable`.
@@ -298,27 +318,31 @@
2. We can add a new constraint definition ([playground](/play/p/Z2eg4X8xK5Z)).
{{raw `
- type Comparer[E any] interface {
- Compare(E) int
- }
+ ~~~go
+ type Comparer[E any] interface {
+ Compare(E) int
+ }
- type ComparableComparer[E any] interface {
- comparable
- Comparer[E]
- }
+ type ComparableComparer[E any] interface {
+ comparable
+ Comparer[E]
+ }
+ ~~~
`}}
This is tidy, but it introduces a new identifier (`ComparableComparer`) into our API, and naming is hard.
3. We can add the constraint inline into our more constrained type ([playground](/play/p/ZfggVma_jNc)):
{{raw `
- type OrderedSet[E interface {
- comparable
- Comparer[E]
- }] struct {
- tree Tree[E]
- elements map[E]struct{}
- }
+ ~~~go
+ type OrderedSet[E interface {
+ comparable
+ Comparer[E]
+ }] struct {
+ tree Tree[E]
+ elements map[E]struct{}
+ }
+ ~~~
`}}
This can become a bit hard to read, especially if it needs to happen often.
@@ -335,12 +359,14 @@
Defining an interface for the set operations you require can add flexibility to your package, leaving the decision of what tradeoffs are right for the specific application to the user:
{{raw `
- type Set[E any] interface {
- Insert(E)
- Delete(E)
- Has(E) bool
- All() iter.Seq[E]
- }
+~~~go
+type Set[E any] interface {
+ Insert(E)
+ Delete(E)
+ Has(E) bool
+ All() iter.Seq[E]
+}
+~~~
`}}
A natural question here is what the constraint on this interface should be.
@@ -359,22 +385,24 @@
Consider a function that removes duplicate elements in a sequence:
{{raw `
- // Unique removes duplicate elements from the input sequence, yielding only
- // the first instance of any element.
- func Unique[E comparable](input iter.Seq[E]) iter.Seq[E] {
- return func(yield func(E) bool) {
- seen := make(map[E]bool)
- for v := range input {
- if seen[v] {
- continue
- }
- if !yield(v) {
- return
- }
- seen[v] = true
+~~~go
+// Unique removes duplicate elements from the input sequence, yielding only
+// the first instance of any element.
+func Unique[E comparable](input iter.Seq[E]) iter.Seq[E] {
+ return func(yield func(E) bool) {
+ seen := make(map[E]bool)
+ for v := range input {
+ if seen[v] {
+ continue
}
+ if !yield(v) {
+ return
+ }
+ seen[v] = true
}
}
+}
+~~~
`}}
([playground](/play/p/hsYoFjkU9kA))
@@ -384,22 +412,24 @@
If we want to generalize this to arbitrary types, we need to replace that with a generic set:
{{raw `
- // Unique removes duplicate elements from the input sequence, yielding only
- // the first instance of any element.
- func Unique[E any](input iter.Seq[E]) iter.Seq[E] {
- return func(yield func(E) bool) {
- var seen Set[E]
- for v := range input {
- if seen.Has(v) {
- continue
- }
- if !yield(v) {
- return
- }
- seen.Insert(v)
+~~~go
+// Unique removes duplicate elements from the input sequence, yielding only
+// the first instance of any element.
+func Unique[E any](input iter.Seq[E]) iter.Seq[E] {
+ return func(yield func(E) bool) {
+ var seen Set[E]
+ for v := range input {
+ if seen.Has(v) {
+ continue
}
+ if !yield(v) {
+ return
+ }
+ seen.Insert(v)
}
}
+}
+~~~
`}}
([playground](/play/p/FZYPNf56nnY))
@@ -412,22 +442,24 @@
We have to ask the user to provide a concrete implementation we can use, as an extra type parameter:
{{raw `
- // Unique removes duplicate elements from the input sequence, yielding only
- // the first instance of any element.
- func Unique[E any, S Set[E]](input iter.Seq[E]) iter.Seq[E] {
- return func(yield func(E) bool) {
- var seen S
- for v := range input {
- if seen.Has(v) {
- continue
- }
- if !yield(v) {
- return
- }
- seen.Insert(v)
+~~~go
+// Unique removes duplicate elements from the input sequence, yielding only
+// the first instance of any element.
+func Unique[E any, S Set[E]](input iter.Seq[E]) iter.Seq[E] {
+ return func(yield func(E) bool) {
+ var seen S
+ for v := range input {
+ if seen.Has(v) {
+ continue
}
+ if !yield(v) {
+ return
+ }
+ seen.Insert(v)
}
}
+}
+~~~
`}}
([playground](/play/p/kjkGy5cNz8T))
@@ -435,10 +467,12 @@
However, if we instantiate this with our set implementation, we run into another problem:
{{raw `
- // OrderedSet[E] does not satisfy Set[E] (method All has pointer receiver)
- Unique[E, OrderedSet[E]](slices.Values(s))
- // panic: invalid memory address or nil pointer dereference
- Unique[E, *OrderedSet[E]](slices.Values(s))
+~~~go
+// OrderedSet[E] does not satisfy Set[E] (method All has pointer receiver)
+Unique[E, OrderedSet[E]](slices.Values(s))
+// panic: invalid memory address or nil pointer dereference
+Unique[E, *OrderedSet[E]](slices.Values(s))
+~~~
`}}
The first problem is clear from the error message: Our type constraint says that the type argument for `S` needs to implement the `Set[E]` interface.
@@ -448,7 +482,9 @@
This stems from the fact that we declare a variable in the implementation:
{{raw `
- var seen S
+~~~go
+var seen S
+~~~
`}}
If `S` is `*OrderedSet[E]`, the variable is initialized with `nil`, as before.
@@ -460,30 +496,32 @@
So we have to introduce an additional type parameter `PS` with a new constraint `PtrToSet`:
{{raw `
- // PtrToSet is implemented by a pointer type implementing the Set[E] interface.
- type PtrToSet[S, E any] interface {
- *S
- Set[E]
- }
+~~~go
+// PtrToSet is implemented by a pointer type implementing the Set[E] interface.
+type PtrToSet[S, E any] interface {
+ *S
+ Set[E]
+}
- // Unique removes duplicate elements from the input sequence, yielding only
- // the first instance of any element.
- func Unique[E, S any, PS PtrToSet[S, E]](input iter.Seq[E]) iter.Seq[E] {
- return func(yield func(E) bool) {
- // We convert to PS, as only that is constrained to have the methods.
- // The conversion is allowed, because the type set of PS only contains *S.
- seen := PS(new(S))
- for v := range input {
- if seen.Has(v) {
- continue
- }
- if !yield(v) {
- return
- }
- seen.Insert(v)
+// Unique removes duplicate elements from the input sequence, yielding only
+// the first instance of any element.
+func Unique[E, S any, PS PtrToSet[S, E]](input iter.Seq[E]) iter.Seq[E] {
+ return func(yield func(E) bool) {
+ // We convert to PS, as only that is constrained to have the methods.
+ // The conversion is allowed, because the type set of PS only contains *S.
+ seen := PS(new(S))
+ for v := range input {
+ if seen.Has(v) {
+ continue
}
+ if !yield(v) {
+ return
+ }
+ seen.Insert(v)
}
}
+}
+~~~
`}}
([playground](/play/p/Kp1jJRVjmYa))
@@ -496,14 +534,18 @@
as long as this extra type parameter is at the end of the type parameter list, it [can be inferred](/blog/type-inference):
{{raw `
- // The third type argument is inferred to be *OrderedSet[int]
- Unique[int, OrderedSet[int]](slices.Values(s))
+~~~go
+// The third type argument is inferred to be *OrderedSet[int]
+Unique[int, OrderedSet[int]](slices.Values(s))
+~~~
`}}
This is a general pattern, and worth remembering: for when you encounter it in someone else's work, or when you want to use it in your own.
{{raw `
- func SomeFunction[T any, PT interface{ *T; SomeMethods }]()
+~~~go
+func SomeFunction[T any, PT interface{ *T; SomeMethods }]()
+~~~
`}}
If you have two type parameters, where one is constrained to be a pointer to the other, the constraint ensures that the relevant methods use a pointer receiver.
@@ -524,12 +566,14 @@
If we rethink this problem, we can avoid the extra type parameter altogether by using `Set[E]` as a regular interface value:
{{raw `
- // InsertAll adds all unique elements from seq into set.
- func InsertAll[E any](set Set[E], seq iter.Seq[E]) {
- for v := range seq {
- set.Insert(v)
- }
+~~~go
+// InsertAll adds all unique elements from seq into set.
+func InsertAll[E any](set Set[E], seq iter.Seq[E]) {
+ for v := range seq {
+ set.Insert(v)
}
+}
+~~~
`}}
([playground](/play/p/woZcHodAgaa))
@@ -543,12 +587,14 @@
It is easy to implement the `Set[E]` interface on that basis:
{{raw `
- type HashSet[E comparable] map[E]bool
+~~~go
+type HashSet[E comparable] map[E]bool
- func (s HashSet[E]) Insert(v E) { s[v] = true }
- func (s HashSet[E]) Delete(v E) { delete(s, v) }
- func (s HashSet[E]) Has(v E) bool { return s[v] }
- func (s HashSet[E]) All() iter.Seq[E] { return maps.Keys(s) }
+func (s HashSet[E]) Insert(v E) { s[v] = true }
+func (s HashSet[E]) Delete(v E) { delete(s, v) }
+func (s HashSet[E]) Has(v E) bool { return s[v] }
+func (s HashSet[E]) All() iter.Seq[E] { return maps.Keys(s) }
+~~~
`}}
([playground](/play/p/KPPpWa7M93d))
diff --git a/_content/blog/generic-slice-functions.md b/_content/blog/generic-slice-functions.md
index 9f377ea..efac1b4 100644
--- a/_content/blog/generic-slice-functions.md
+++ b/_content/blog/generic-slice-functions.md
@@ -12,7 +12,7 @@
With [Type parameters](/blog/deconstructing-type-parameters) we can write functions like [slices.Index](/pkg/slices#Index) once for all types of slices of comparable elements:
-```
+```go
// Index returns the index of the first occurrence of v in s,
// or -1 if not present.
func Index[S ~[]E, E comparable](s S, v E) int {
@@ -29,7 +29,7 @@
The [slices](/pkg/slices) package contains many such helpers to perform common operations on slices:
-```
+```go
s := []string{"Bat", "Fox", "Owl", "Fox"}
s2 := slices.Clone(s)
slices.Sort(s2)
@@ -51,13 +51,13 @@
Consider the task of deleting a portion of a slice. Prior to generics, the standard way to delete the portion `s[2:5]` from the slice `s` was to call the [append](/ref/spec#Appending_and_copying_slices) function to copy the end portion over the middle portion:
-```
+```go
s = append(s[:2], s[5:]...)
```
The syntax was complex and error-prone, involving subslices and a variadic parameter. We added [slices.Delete](/pkg/slices#Delete) to make it easier to delete elements:
-```
+```go
func Delete[S ~[]E, E any](s S, i, j int) S {
return append(s[:i], s[j:]...)
}
@@ -69,7 +69,7 @@
This call deletes the elements at `s[2]`, `s[3]`, `s[4]` from the slice `s`:
-```
+```go
s = slices.Delete(s, 2, 5)
```
@@ -81,7 +81,7 @@
When calling these functions we must consider the original slice invalid, because the underlying array has been modified. It would be a mistake to call the function but ignore the return value:
-```
+```go
slices.Delete(s, 2, 5) // incorrect!
// s still has the same length, but modified contents
```
@@ -121,7 +121,7 @@
If you ignore the return value of `Delete`:
-```
+```go
slices.Delete(s, 2, 3) // !! INCORRECT !!
```
@@ -129,7 +129,7 @@
If you ignore the return value of `Compact`:
-```
+```go
slices.Sort(s) // correct
slices.Compact(s) // !! INCORRECT !!
```
@@ -138,7 +138,7 @@
If you assign the return value of `Delete` to another variable, and keep using the original slice:
-```
+```go
u := slices.Delete(s, 2, 3) // !! INCORRECT, if you keep using s !!
```
@@ -146,7 +146,7 @@
If you accidentally shadow the slice variable, and keep using the original slice:
-```
+```go
s := slices.Delete(s, 2, 3) // !! INCORRECT, using := instead of = !!
```
diff --git a/_content/blog/gif-decoder.md b/_content/blog/gif-decoder.md
index 64abf2a..4a77741 100644
--- a/_content/blog/gif-decoder.md
+++ b/_content/blog/gif-decoder.md
@@ -82,7 +82,9 @@
as [the documentation](/pkg/compress/lzw/#NewReader) says,
"satisfies reads by decompressing the data read from r":
- func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser
+```go
+func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser
+```
Here `order` defines the bit-packing order and `litWidth` is the word size in bits,
which for a GIF file corresponds to the pixel depth, typically 8.
@@ -97,11 +99,13 @@
Here's the data structure for a `blockReader`.
- type blockReader struct {
- r reader // Input source; implements io.Reader and io.ByteReader.
- slice []byte // Buffer of unread data.
- tmp [256]byte // Storage for slice.
- }
+```go
+type blockReader struct {
+ r reader // Input source; implements io.Reader and io.ByteReader.
+ slice []byte // Buffer of unread data.
+ tmp [256]byte // Storage for slice.
+}
+```
The reader, `r`, will be the source of the image data,
perhaps a file or HTTP connection.
@@ -109,27 +113,29 @@
Here's the `Read` method in its entirety.
It's a nice example of the use of slices and arrays in Go.
- 1 func (b *blockReader) Read(p []byte) (int, os.Error) {
- 2 if len(p) == 0 {
- 3 return 0, nil
- 4 }
- 5 if len(b.slice) == 0 {
- 6 blockLen, err := b.r.ReadByte()
- 7 if err != nil {
- 8 return 0, err
- 9 }
- 10 if blockLen == 0 {
- 11 return 0, os.EOF
- 12 }
- 13 b.slice = b.tmp[0:blockLen]
- 14 if _, err = io.ReadFull(b.r, b.slice); err != nil {
- 15 return 0, err
- 16 }
- 17 }
- 18 n := copy(p, b.slice)
- 19 b.slice = b.slice[n:]
- 20 return n, nil
- 21 }
+```go
+1 func (b *blockReader) Read(p []byte) (int, os.Error) {
+2 if len(p) == 0 {
+3 return 0, nil
+4 }
+5 if len(b.slice) == 0 {
+6 blockLen, err := b.r.ReadByte()
+7 if err != nil {
+8 return 0, err
+9 }
+10 if blockLen == 0 {
+11 return 0, os.EOF
+12 }
+13 b.slice = b.tmp[0:blockLen]
+14 if _, err = io.ReadFull(b.r, b.slice); err != nil {
+15 return 0, err
+16 }
+17 }
+18 n := copy(p, b.slice)
+19 b.slice = b.slice[n:]
+20 return n, nil
+21 }
+```
Lines 2-4 are just a sanity check: if there's no place to put data, return zero.
That should never happen, but it's good to be safe.
@@ -168,7 +174,9 @@
by wrapping the input reader,
say a file, like this:
- deblockingReader := &blockReader{r: imageFile}
+```go
+deblockingReader := &blockReader{r: imageFile}
+```
This wrapping turns a block-delimited GIF image stream into a simple stream
of bytes accessible by calls to the `Read` method of the `blockReader`.
@@ -180,10 +188,12 @@
We stitch them together with this thunderclap,
straight from the code:
- lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
- if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
- break
- }
+```go
+lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
+if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
+ break
+}
+```
That's it.
diff --git a/_content/blog/go-cloud.md b/_content/blog/go-cloud.md
index f179579..6ac48e5 100644
--- a/_content/blog/go-cloud.md
+++ b/_content/blog/go-cloud.md
@@ -80,44 +80,48 @@
to copy a file from a local disk to a cloud provider.
Let's start by opening an S3 bucket using the included [s3blob package](https://godoc.org/github.com/google/go-cloud/blob/s3blob):
- // setupBucket opens an AWS bucket.
- func setupBucket(ctx context.Context) (*blob.Bucket, error) {
- // Obtain AWS credentials.
- sess, err := session.NewSession(&aws.Config{
- Region: aws.String("us-east-2"),
- })
- if err != nil {
- return nil, err
- }
- // Open a handle to s3://go-cloud-bucket.
- return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
+```go
+// setupBucket opens an AWS bucket.
+func setupBucket(ctx context.Context) (*blob.Bucket, error) {
+ // Obtain AWS credentials.
+ sess, err := session.NewSession(&aws.Config{
+ Region: aws.String("us-east-2"),
+ })
+ if err != nil {
+ return nil, err
}
+ // Open a handle to s3://go-cloud-bucket.
+ return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
+}
+```
Once a program has a `*blob.Bucket`, it can create a `*blob.Writer`,
which implements `io.Writer`.
From there, the program can use the `*blob.Writer` to write data to the bucket,
checking that `Close` does not report an error.
- ctx := context.Background()
- b, err := setupBucket(ctx)
- if err != nil {
- log.Fatalf("Failed to open bucket: %v", err)
- }
- data, err := ioutil.ReadFile("gopher.png")
- if err != nil {
- log.Fatalf("Failed to read file: %v", err)
- }
- w, err := b.NewWriter(ctx, "gopher.png", nil)
- if err != nil {
- log.Fatalf("Failed to obtain writer: %v", err)
- }
- _, err = w.Write(data)
- if err != nil {
- log.Fatalf("Failed to write to bucket: %v", err)
- }
- if err := w.Close(); err != nil {
- log.Fatalf("Failed to close: %v", err)
- }
+```go
+ctx := context.Background()
+b, err := setupBucket(ctx)
+if err != nil {
+ log.Fatalf("Failed to open bucket: %v", err)
+}
+data, err := ioutil.ReadFile("gopher.png")
+if err != nil {
+ log.Fatalf("Failed to read file: %v", err)
+}
+w, err := b.NewWriter(ctx, "gopher.png", nil)
+if err != nil {
+ log.Fatalf("Failed to obtain writer: %v", err)
+}
+_, err = w.Write(data)
+if err != nil {
+ log.Fatalf("Failed to write to bucket: %v", err)
+}
+if err := w.Close(); err != nil {
+ log.Fatalf("Failed to close: %v", err)
+}
+```
Notice how the logic of using the bucket does not refer to AWS S3.
Go Cloud makes swapping out cloud storage a matter of changing the function
@@ -126,20 +130,22 @@
`*blob.Bucket` using [`gcsblob.OpenBucket`](https://godoc.org/github.com/google/go-cloud/blob/gcsblob#OpenBucket)
without changing the code that copies the file:
- // setupBucket opens a GCS bucket.
- func setupBucket(ctx context.Context) (*blob.Bucket, error) {
- // Open GCS bucket.
- creds, err := gcp.DefaultCredentials(ctx)
- if err != nil {
- return nil, err
- }
- c, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds))
- if err != nil {
- return nil, err
- }
- // Open a handle to gs://go-cloud-bucket.
- return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
+```go
+// setupBucket opens a GCS bucket.
+func setupBucket(ctx context.Context) (*blob.Bucket, error) {
+ // Open GCS bucket.
+ creds, err := gcp.DefaultCredentials(ctx)
+ if err != nil {
+ return nil, err
}
+ c, err := gcp.NewHTTPClient(gcp.DefaultTransport(), gcp.CredentialsTokenSource(creds))
+ if err != nil {
+ return nil, err
+ }
+ // Open a handle to gs://go-cloud-bucket.
+ return gcsblob.OpenBucket(ctx, "go-cloud-bucket", c)
+}
+```
While different steps are needed to access buckets on different cloud providers,
the resulting type used by your application is the same: `*blob.Bucket`.
diff --git a/_content/blog/go-fonts.md b/_content/blog/go-fonts.md
index 7305bd0..c8596ae 100644
--- a/_content/blog/go-fonts.md
+++ b/_content/blog/go-fonts.md
@@ -51,7 +51,9 @@
If you want to use Go (the fonts) with Go (the software), each font is provided by a separate package.
To use the Go Regular font in a program, import `golang.org/x/image/font/gofont/goregular`, and write:
- font, err := truetype.Parse(goregular.TTF)
+```go
+font, err := truetype.Parse(goregular.TTF)
+```
The [`github.com/golang/freetype/truetype`](https://godoc.org/github.com/golang/freetype/truetype)
package provides the [`truetype.Parse`](https://godoc.org/github.com/golang/freetype/truetype#Parse) function today.
diff --git a/_content/blog/go1.13-errors.md b/_content/blog/go1.13-errors.md
index a17cc77..9f38abd 100644
--- a/_content/blog/go1.13-errors.md
+++ b/_content/blog/go1.13-errors.md
@@ -18,12 +18,14 @@
allows Go programmers to add whatever information they desire. All it requires
is a type that implements an `Error` method:
- type QueryError struct {
- Query string
- Err error
- }
+```go
+type QueryError struct {
+ Query string
+ Err error
+}
- func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
+func (e *QueryError) Error() string { return e.Query + ": " + e.Err.Error() }
+```
Error types like this one are ubiquitous, and the information they store varies
widely, from timestamps to filenames to server addresses. Often, that
@@ -46,31 +48,37 @@
ways. The most common is to compare an error to `nil` to see if an operation
failed.
- if err != nil {
- // something went wrong
- }
+```go
+if err != nil {
+ // something went wrong
+}
+```
Sometimes we compare an error to a known _sentinel_ value, to see if a specific error has occurred.
- var ErrNotFound = errors.New("not found")
+```go
+var ErrNotFound = errors.New("not found")
- if err == ErrNotFound {
- // something wasn't found
- }
+if err == ErrNotFound {
+ // something wasn't found
+}
+```
An error value may be of any type which satisfies the language-defined `error`
interface. A program can use a type assertion or type switch to view an error
value as a more specific type.
- type NotFoundError struct {
- Name string
- }
+```go
+type NotFoundError struct {
+ Name string
+}
- func (e *NotFoundError) Error() string { return e.Name + ": not found" }
+func (e *NotFoundError) Error() string { return e.Name + ": not found" }
- if e, ok := err.(*NotFoundError); ok {
- // e.Name wasn't found
- }
+if e, ok := err.(*NotFoundError); ok {
+ // e.Name wasn't found
+}
+```
### Adding information
@@ -79,27 +87,33 @@
simple way to do this is to construct a new error that includes the text of the
previous one:
- if err != nil {
- return fmt.Errorf("decompress %v: %v", name, err)
- }
+```go
+if err != nil {
+ return fmt.Errorf("decompress %v: %v", name, err)
+}
+```
Creating a new error with `fmt.Errorf` discards everything from the original
error except the text. As we saw above with `QueryError`, we may sometimes want
to define a new error type that contains the underlying error, preserving it for
inspection by code. Here is `QueryError` again:
- type QueryError struct {
- Query string
- Err error
- }
+```go
+type QueryError struct {
+ Query string
+ Err error
+}
+```
Programs can look inside a `*QueryError` value to make decisions based on the
underlying error. You'll sometimes see this referred to as "unwrapping" the
error.
- if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
- // query failed because of a permission problem
- }
+```go
+if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+ // query failed because of a permission problem
+}
+```
The `os.PathError` type in the standard library is another example of one error which contains another.
@@ -117,7 +131,9 @@
Following this convention, we can give the `QueryError` type above an `Unwrap`
method that returns its contained error:
- func (e *QueryError) Unwrap() error { return e.Err }
+```go
+func (e *QueryError) Unwrap() error { return e.Err }
+```
The result of unwrapping an error may itself have an `Unwrap` method; we call
the sequence of errors produced by repeated unwrapping the _error chain_.
@@ -128,21 +144,25 @@
The `errors.Is` function compares an error to a value.
- // Similar to:
- // if err == ErrNotFound { … }
- if errors.Is(err, ErrNotFound) {
- // something wasn't found
- }
+```go
+// Similar to:
+// if err == ErrNotFound { … }
+if errors.Is(err, ErrNotFound) {
+ // something wasn't found
+}
+```
The `As` function tests whether an error is a specific type.
- // Similar to:
- // if e, ok := err.(*QueryError); ok { … }
- var e *QueryError
- // Note: *QueryError is the type of the error.
- if errors.As(err, &e) {
- // err is a *QueryError, and e is set to the error's value
- }
+```go
+// Similar to:
+// if e, ok := err.(*QueryError); ok { … }
+var e *QueryError
+// Note: *QueryError is the type of the error.
+if errors.As(err, &e) {
+ // err is a *QueryError, and e is set to the error's value
+}
+```
In the simplest case, the `errors.Is` function behaves like a comparison to a
sentinel error, and the `errors.As` function behaves like a type assertion. When
@@ -150,15 +170,19 @@
a chain. Let's look again at the example from above of unwrapping a `QueryError`
to examine the underlying error:
- if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
- // query failed because of a permission problem
- }
+```go
+if e, ok := err.(*QueryError); ok && e.Err == ErrPermission {
+ // query failed because of a permission problem
+}
+```
Using the `errors.Is` function, we can write this as:
- if errors.Is(err, ErrPermission) {
- // err, or some error that it wraps, is a permission problem
- }
+```go
+if errors.Is(err, ErrPermission) {
+ // err, or some error that it wraps, is a permission problem
+}
+```
The `errors` package also includes a new `Unwrap` function which returns the
result of calling an error's `Unwrap` method, or `nil` when the error has no
@@ -173,25 +197,31 @@
As mentioned earlier, it is common to use the `fmt.Errorf` function to add additional information to an error.
- if err != nil {
- return fmt.Errorf("decompress %v: %v", name, err)
- }
+```go
+if err != nil {
+ return fmt.Errorf("decompress %v: %v", name, err)
+}
+```
In Go 1.13, the `fmt.Errorf` function supports a new `%w` verb. When this verb
is present, the error returned by `fmt.Errorf` will have an `Unwrap` method
returning the argument of `%w`, which must be an error. In all other ways, `%w`
is identical to `%v`.
- if err != nil {
- // Return an error which unwraps to err.
- return fmt.Errorf("decompress %v: %w", name, err)
- }
+```go
+if err != nil {
+ // Return an error which unwraps to err.
+ return fmt.Errorf("decompress %v: %w", name, err)
+}
+```
Wrapping an error with `%w` makes it available to `errors.Is` and `errors.As`:
- err := fmt.Errorf("access denied: %w", ErrPermission)
- ...
- if errors.Is(err, ErrPermission) ...
+```go
+err := fmt.Errorf("access denied: %w", ErrPermission)
+...
+if errors.Is(err, ErrPermission) ...
+```
### Whether to Wrap
@@ -219,8 +249,10 @@
the function instead returns `fmt.Errorf("accessing DB: %w", err)`, then a
caller could reasonably write
- err := pkg.LookupUser(...)
- if errors.Is(err, sql.ErrNoRows) …
+```go
+err := pkg.LookupUser(...)
+if errors.Is(err, sql.ErrNoRows) …
+```
At that point, the function must always return `sql.ErrNoRows` if you don't want
to break your clients, even if you switch to a different database package. In
@@ -247,23 +279,25 @@
which compares an error against a template, considering only fields which are
non-zero in the template:
- type Error struct {
- Path string
- User string
- }
+```go
+type Error struct {
+ Path string
+ User string
+}
- func (e *Error) Is(target error) bool {
- t, ok := target.(*Error)
- if !ok {
- return false
- }
- return (e.Path == t.Path || t.Path == "") &&
- (e.User == t.User || t.User == "")
+func (e *Error) Is(target error) bool {
+ t, ok := target.(*Error)
+ if !ok {
+ return false
}
+ return (e.Path == t.Path || t.Path == "") &&
+ (e.User == t.User || t.User == "")
+}
- if errors.Is(err, &Error{User: "someuser"}) {
- // err's User field is "someuser".
- }
+if errors.Is(err, &Error{User: "someuser"}) {
+ // err's User field is "someuser".
+}
+```
The `errors.As` function similarly consults an `As` method when present.
@@ -280,18 +314,20 @@
If we wish a function to return an identifiable error condition, such as "item
not found," we might return an error wrapping a sentinel.
- var ErrNotFound = errors.New("not found")
+```go
+var ErrNotFound = errors.New("not found")
- // FetchItem returns the named item.
- //
- // If no item with the name exists, FetchItem returns an error
- // wrapping ErrNotFound.
- func FetchItem(name string) (*Item, error) {
- if itemNotFound(name) {
- return nil, fmt.Errorf("%q: %w", name, ErrNotFound)
- }
- // ...
+// FetchItem returns the named item.
+//
+// If no item with the name exists, FetchItem returns an error
+// wrapping ErrNotFound.
+func FetchItem(name string) (*Item, error) {
+ if itemNotFound(name) {
+ return nil, fmt.Errorf("%q: %w", name, ErrNotFound)
}
+ // ...
+}
+```
There are other existing patterns for providing errors which can be semantically
examined by the caller, such as directly returning a sentinel value, a specific
@@ -303,39 +339,43 @@
not expose the underlying error, unless you are willing to commit to returning
that specific error in the future.
- f, err := os.Open(filename)
- if err != nil {
- // The *os.PathError returned by os.Open is an internal detail.
- // To avoid exposing it to the caller, repackage it as a new
- // error with the same text. We use the %v formatting verb, since
- // %w would permit the caller to unwrap the original *os.PathError.
- return fmt.Errorf("%v", err)
- }
+```go
+f, err := os.Open(filename)
+if err != nil {
+ // The *os.PathError returned by os.Open is an internal detail.
+ // To avoid exposing it to the caller, repackage it as a new
+ // error with the same text. We use the %v formatting verb, since
+ // %w would permit the caller to unwrap the original *os.PathError.
+ return fmt.Errorf("%v", err)
+}
+```
If a function is defined as returning an error wrapping some sentinel or type,
do not return the underlying error directly.
- var ErrPermission = errors.New("permission denied")
+```go
+var ErrPermission = errors.New("permission denied")
- // DoSomething returns an error wrapping ErrPermission if the user
- // does not have permission to do something.
- func DoSomething() error {
- if !userHasPermission() {
- // If we return ErrPermission directly, callers might come
- // to depend on the exact error value, writing code like this:
- //
- // if err := pkg.DoSomething(); err == pkg.ErrPermission { … }
- //
- // This will cause problems if we want to add additional
- // context to the error in the future. To avoid this, we
- // return an error wrapping the sentinel so that users must
- // always unwrap it:
- //
- // if err := pkg.DoSomething(); errors.Is(err, pkg.ErrPermission) { ... }
- return fmt.Errorf("%w", ErrPermission)
- }
- // ...
+// DoSomething returns an error wrapping ErrPermission if the user
+// does not have permission to do something.
+func DoSomething() error {
+ if !userHasPermission() {
+ // If we return ErrPermission directly, callers might come
+ // to depend on the exact error value, writing code like this:
+ //
+ // if err := pkg.DoSomething(); err == pkg.ErrPermission { … }
+ //
+ // This will cause problems if we want to add additional
+ // context to the error in the future. To avoid this, we
+ // return an error wrapping the sentinel so that users must
+ // always unwrap it:
+ //
+ // if err := pkg.DoSomething(); errors.Is(err, pkg.ErrPermission) { ... }
+ return fmt.Errorf("%w", ErrPermission)
}
+ // ...
+}
+```
## Conclusion
diff --git a/_content/blog/go1.22.md b/_content/blog/go1.22.md
index 25945b2..44da4b1 100644
--- a/_content/blog/go1.22.md
+++ b/_content/blog/go1.22.md
@@ -21,22 +21,24 @@
will print "a", "b", and "c" in some order:
{{raw `
- func main() {
- done := make(chan bool)
+~~~go
+func main() {
+ done := make(chan bool)
- values := []string{"a", "b", "c"}
- for _, v := range values {
- go func() {
- fmt.Println(v)
- done <- true
- }()
- }
-
- // wait for all goroutines to complete before exiting
- for _ = range values {
- <-done
- }
+ values := []string{"a", "b", "c"}
+ for _, v := range values {
+ go func() {
+ fmt.Println(v)
+ done <- true
+ }()
}
+
+ // wait for all goroutines to complete before exiting
+ for _ = range values {
+ <-done
+ }
+}
+~~~
`}}
For more information about this change and the tooling that helps keep code from
@@ -46,16 +48,18 @@
The second language change is support for ranging over integers:
{{raw `
- package main
+~~~go
+package main
- import "fmt"
+import "fmt"
- func main() {
- for i := range 10 {
- fmt.Println(10 - i)
- }
- fmt.Println("go1.22 has lift-off!")
+func main() {
+ for i := range 10 {
+ fmt.Println(10 - i)
}
+ fmt.Println("go1.22 has lift-off!")
+}
+~~~
`}}
The values of `i` in this countdown program go from 0 to 9, inclusive. For more
diff --git a/_content/blog/go1.7-binary-size.md b/_content/blog/go1.7-binary-size.md
index 7bbb6c7..cb4aff7 100644
--- a/_content/blog/go1.7-binary-size.md
+++ b/_content/blog/go1.7-binary-size.md
@@ -73,13 +73,15 @@
The canonical hello world program goes from 2.3MB to 1.6MB:
- package main
+```go
+package main
- import "fmt"
+import "fmt"
- func main() {
- fmt.Println("Hello, World!")
- }
+func main() {
+ fmt.Println("Hello, World!")
+}
+```
When compiled without debugging information the statically
linked binary is now under a megabyte.
diff --git a/_content/blog/go1.8.md b/_content/blog/go1.8.md
index 179fb73..2ca415f 100644
--- a/_content/blog/go1.8.md
+++ b/_content/blog/go1.8.md
@@ -39,7 +39,9 @@
function in the `sort` package. For example, to sort a slice of structs by their `Name` field:
{{raw `
- sort.Slice(s, func(i, j int) bool { return s[i].Name < s[j].Name })
+~~~go
+sort.Slice(s, func(i, j int) bool { return s[i].Name < s[j].Name })
+~~~
`}}
Go 1.8 includes many more additions, improvements, and fixes.
diff --git a/_content/blog/go1.9.md b/_content/blog/go1.9.md
index 4a233eb..3f32cfb 100644
--- a/_content/blog/go1.9.md
+++ b/_content/blog/go1.9.md
@@ -18,7 +18,9 @@
The most important change to the language is the introduction of type aliases: a feature
created to support gradual code repair. A type alias declaration has the form:
- type T1 = T2
+```go
+type T1 = T2
+```
This declaration introduces an alias name `T1` for the type `T2`, in the same way that `byte` has
always been an alias for `uint8`.
@@ -53,9 +55,11 @@
making computing durations between two `Time` values a safe operation in the presence of wall clock adjustments.
For example, this code now computes the right elapsed time even across a leap second clock reset:
- start := time.Now()
- f()
- elapsed := time.Since(start)
+```go
+start := time.Now()
+f()
+elapsed := time.Since(start)
+```
See the [package docs](http://beta.golang.org/pkg/time/#hdr-Monotonic_Clocks) and
[design document](https://github.com/golang/proposal/blob/master/design/12914-monotonic.md) for details.
diff --git a/_content/blog/gob.md b/_content/blog/gob.md
index a155f31..5c6422e 100644
--- a/_content/blog/gob.md
+++ b/_content/blog/gob.md
@@ -144,8 +144,10 @@
Flexibility also happens because, when decoding a struct,
only those fields that are sent by the encoder are stored in the destination. Given the value
- type T struct{ X, Y, Z int } // Only exported fields are encoded and decoded.
- var t = T{X: 7, Y: 0, Z: 8}
+```go
+type T struct{ X, Y, Z int } // Only exported fields are encoded and decoded.
+var t = T{X: 7, Y: 0, Z: 8}
+```
the encoding of `t` sends only the 7 and 8.
Because it's zero, the value of `Y` isn't even sent;
@@ -153,8 +155,10 @@
The receiver could instead decode the value into this structure:
- type U struct{ X, Y *int8 } // Note: pointers to int8s
- var u U
+```go
+type U struct{ X, Y *int8 } // Note: pointers to int8s
+var u U
+```
and acquire a value of `u` with only `X` set (to the address of an `int8` variable set to 7);
the `Z` field is ignored - where would you put it? When decoding structs,
@@ -208,10 +212,12 @@
values of those types.
Thus gobs can encode types such as trees:
- type Node struct {
- Value int
- Left, Right *Node
- }
+```go
+type Node struct {
+ Value int
+ Left, Right *Node
+}
+```
(It's an exercise for the reader to discover how the zero-defaulting rule makes this work,
even though gobs don't represent pointers.)
@@ -254,45 +260,47 @@
all you need to do is present values and variables to the [gob package](/pkg/encoding/gob/)
and it does all the work.
- package main
+```go
+package main
- import (
- "bytes"
- "encoding/gob"
- "fmt"
- "log"
- )
+import (
+ "bytes"
+ "encoding/gob"
+ "fmt"
+ "log"
+)
- type P struct {
- X, Y, Z int
- Name string
- }
+type P struct {
+ X, Y, Z int
+ Name string
+}
- type Q struct {
- X, Y *int32
- Name string
- }
+type Q struct {
+ X, Y *int32
+ Name string
+}
- func main() {
- // Initialize the encoder and decoder. Normally enc and dec would be
- // bound to network connections and the encoder and decoder would
- // run in different processes.
- var network bytes.Buffer // Stand-in for a network connection
- enc := gob.NewEncoder(&network) // Will write to network.
- dec := gob.NewDecoder(&network) // Will read from network.
- // Encode (send) the value.
- err := enc.Encode(P{3, 4, 5, "Pythagoras"})
- if err != nil {
- log.Fatal("encode error:", err)
- }
- // Decode (receive) the value.
- var q Q
- err = dec.Decode(&q)
- if err != nil {
- log.Fatal("decode error:", err)
- }
- fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
- }
+func main() {
+ // Initialize the encoder and decoder. Normally enc and dec would be
+ // bound to network connections and the encoder and decoder would
+ // run in different processes.
+ var network bytes.Buffer // Stand-in for a network connection
+ enc := gob.NewEncoder(&network) // Will write to network.
+ dec := gob.NewDecoder(&network) // Will read from network.
+ // Encode (send) the value.
+ err := enc.Encode(P{3, 4, 5, "Pythagoras"})
+ if err != nil {
+ log.Fatal("encode error:", err)
+ }
+ // Decode (receive) the value.
+ var q Q
+ err = dec.Decode(&q)
+ if err != nil {
+ log.Fatal("decode error:", err)
+ }
+ fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
+}
+```
You can compile and run this example code in the [Go Playground](/play/p/_-OJV-rwMq).
diff --git a/_content/blog/godoc.md b/_content/blog/godoc.md
index f5ade6c..777860e 100644
--- a/_content/blog/godoc.md
+++ b/_content/blog/godoc.md
@@ -47,10 +47,12 @@
Godoc will then present that comment as text alongside the item it documents.
For example, this is the documentation for the `fmt` package's [`Fprint`](/pkg/fmt/#Fprint) function:
- // Fprint formats using the default formats for its operands and writes to w.
- // Spaces are added between operands when neither is a string.
- // It returns the number of bytes written and any write error encountered.
- func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+```go
+// Fprint formats using the default formats for its operands and writes to w.
+// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
+```
Notice this comment is a complete sentence that begins with the name of
the element it describes.
@@ -63,9 +65,11 @@
These comments can be short, like the [`sort`](/pkg/sort/)
package's brief description:
- // Package sort provides primitives for sorting slices and user-defined
- // collections.
- package sort
+```go
+// Package sort provides primitives for sorting slices and user-defined
+// collections.
+package sort
+```
They can also be detailed like the [gob package](/pkg/encoding/gob/)'s overview.
That package uses another convention for packages that need large amounts
@@ -85,7 +89,9 @@
The "who” part should be the user name of someone who could provide more information.
For example, this is a known issue from the [bytes package](/pkg/bytes/#pkg-note-BUG):
- // BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+```go
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+```
Sometimes a struct field, function, type, or even a whole package becomes
redundant or unnecessary, but must be kept for compatibility with existing
diff --git a/_content/blog/gofix.md b/_content/blog/gofix.md
index 4f1c433..81ae443 100644
--- a/_content/blog/gofix.md
+++ b/_content/blog/gofix.md
@@ -108,7 +108,7 @@
**minmax** replaces an `if` statement by a use of Go 1.21’s `min` or `max` functions:
<div class="beforeafter">
-<pre>
+<pre lang=go>
x := f()
if x < 0 {
x = 0
@@ -118,7 +118,7 @@
}
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
x := min(max(f(), 0), 100)
</pre>
</div>
@@ -126,13 +126,13 @@
**rangeint** replaces a 3-clause `for` loop by a Go 1.22 `range`-over-int loop:
<div class="beforeafter">
-<pre>
+<pre lang=go>
for i := 0; i < n; i++ {
f()
}
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
for range n {
f()
}
@@ -142,14 +142,14 @@
**stringscut** (whose `-diff` output we saw earlier) replaces uses of `strings.Index` and slicing by Go 1.18’s `strings.Cut`:
<div class="beforeafter">
-<pre>
+<pre lang=go>
i := strings.Index(s, ":")
if i >= 0 {
return s[:i]
}
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
before, _, ok := strings.Cut(s, ":")
if ok {
return before
@@ -164,18 +164,18 @@
Go 1.26 includes a small but widely useful change to the language specification. The built-in `new` function creates a new variable and returns its address. Historically, its sole argument was required to be a type, such as `new(string)`, and the new variable was initialized to its “zero” value, such as `""`. In Go 1.26, the `new` function may be called with any value, causing it to create a variable initialized to that value, avoiding the need for an additional statement. For example:
<div class="beforeafter">
-<pre>
+<pre lang=go>
ptr := new(string)
*ptr = "go1.25"
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
ptr := new("go1.26")
</pre>
</div>
This feature filled a gap that had been discussed for over a decade and resolved one of the most popular [proposals](/issue/45624) for a change to the language. It is especially convenient in code that uses a pointer type `*T` to indicate an optional value of type `T`, as is common when working with serialization packages such as [json.Marshal](https://pkg.go.dev/encoding/json#Marshal) or [protocol buffers](https://protobuf.dev/getting-started/gotutorial/). This is such a common pattern that people often capture it in a helper, such as the `newInt` function below, saving the caller from the need to break out of an expression context to introduce additional statements:
-```
+```go
type RequestJSON struct {
URL string
Attempts *int // (optional)
@@ -190,7 +190,7 @@
```
Helpers such as `newInt` are so frequently needed with protocol buffers that the `proto` API itself provides them as [`proto.Int64`](https://pkg.go.dev/google.golang.org/protobuf/proto#Int64), [`proto.String`](https://pkg.go.dev/google.golang.org/protobuf/proto#String), and so on. But Go 1.26 makes all these helpers unnecessary:
-```
+```go
data, err := json.Marshal(&RequestJSON{
URL: url,
Attempts: new(10),
@@ -211,7 +211,7 @@
Applying one modernization may create opportunities to apply another. For example, this snippet of code, which clamps `x` to the range 0–100, causes the minmax modernizer to suggest a fix to use `max`. Once that fix is applied it suggests a second fix, this time to use `min`.
<div class="beforeafter">
-<pre>
+<pre lang=go>
x := f()
if x < 0 {
x = 0
@@ -221,7 +221,7 @@
}
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
x := min(max(f(), 0), 100)
</pre>
</div>
@@ -229,7 +229,7 @@
Synergies may also occur between different analyzers. For example, a common mistake is to repeatedly concatenate strings within a loop, resulting in quadratic time complexity—a bug and a potential vector for a denial-of-service attack. The `stringsbuilder` modernizer recognizes the problem and suggests using Go 1.10’s `strings.Builder`:
<div class="beforeafter">
-<pre>
+<pre lang=go>
s := ""
for _, b := range bytes {
s += fmt.Sprintf("%02x", b)
@@ -237,7 +237,7 @@
use(s)
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
var s strings.Builder
for _, b := range bytes {
s.WriteString(fmt.Sprintf("%02x", b))
@@ -300,7 +300,7 @@
As the number of analyzers in `go vet` and `go fix` continues to grow, we have been investing in infrastructure both to improve the performance of each analyzer and to make it easier to write each new analyzer.
For example, most analyzers start by traversing the syntax trees of each file in the package looking for a particular kind of node such as a range statement or function literal. The existing [inspector](https://pkg.go.dev/golang.org/x/tools/go/ast/inspector) package makes this scan efficient by pre-computing a compact index of a complete traversal so that later traversals can quickly skip subtrees that don’t contain any nodes of interest. Recently we extended it with the [Cursor](https://pkg.go.dev/golang.org/x/tools/go/ast/inspector#Cursor) datatype to allow flexible and efficient navigation between nodes in all four cardinal directions—up, down, left, and right, similar to navigating the elements of an HTML DOM—making it easy and efficient to express a query such as “find each go statement that is the first statement of a loop body”:
-```
+```go
var curFile inspector.Cursor = ...
// Find each go statement that is the first statement of a loop body.
diff --git a/_content/blog/greenteagc.md b/_content/blog/greenteagc.md
index 103056e..93098e4 100644
--- a/_content/blog/greenteagc.md
+++ b/_content/blog/greenteagc.md
@@ -133,7 +133,7 @@
For example, the following code snippet allocates a single heap object: the backing
store for a slice of pointers.
-```
+```go
var x = make([]*int, 10) // global
```
@@ -147,7 +147,7 @@
For example, to get the pointer to the beginning of the object allocated in the
last code snippet, we can write:
-```
+```go
&x[0] // 0xc000104000
```
diff --git a/_content/blog/image-draw.md b/_content/blog/image-draw.md
index 5d2fe65..788ff90 100644
--- a/_content/blog/image-draw.md
+++ b/_content/blog/image-draw.md
@@ -72,18 +72,22 @@
but an explicit mask and mask-point are usually unnecessary,
so the [`Draw`](/pkg/image/draw/#Draw) function takes five:
- // Draw calls DrawMask with a nil mask.
- func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
- func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point,
- mask image.Image, mp image.Point, op Op)
+```go
+// Draw calls DrawMask with a nil mask.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point,
+ mask image.Image, mp image.Point, op Op)
+```
The destination image must be mutable, so the image/draw package defines
a [`draw.Image`](/pkg/image/draw/#Image) interface which has a `Set` method.
- type Image interface {
- image.Image
- Set(x, y int, c color.Color)
- }
+```go
+type Image interface {
+ image.Image
+ Set(x, y int, c color.Color)
+}
+```
## Filling a Rectangle
@@ -94,20 +98,26 @@
there is no need for an explicit "repeat bit" in Go's slice-based image types;
the concept is subsumed by `Uniform`.
- // image.ZP is the zero point -- the origin.
- draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
+```go
+// image.ZP is the zero point -- the origin.
+draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
+```
To initialize a new image to all-blue:
- m := image.NewRGBA(image.Rect(0, 0, 640, 480))
- blue := color.RGBA{0, 0, 255, 255}
- draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
+```go
+m := image.NewRGBA(image.Rect(0, 0, 640, 480))
+blue := color.RGBA{0, 0, 255, 255}
+draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
+```
To reset an image to transparent (or black,
if the destination image's color model cannot represent transparency),
use `image.Transparent`, which is an `image.Uniform`:
- draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)
+```go
+draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)
+```
{{image "image-draw/2a.png"}}
@@ -117,13 +127,17 @@
at a point `dp` in the destination,
convert the source rectangle into the destination image's co-ordinate space:
- r := image.Rectangle{dp, dp.Add(sr.Size())}
- draw.Draw(dst, r, src, sr.Min, draw.Src)
+```go
+r := image.Rectangle{dp, dp.Add(sr.Size())}
+draw.Draw(dst, r, src, sr.Min, draw.Src)
+```
Alternatively:
- r := sr.Sub(sr.Min).Add(dp)
- draw.Draw(dst, r, src, sr.Min, draw.Src)
+```go
+r := sr.Sub(sr.Min).Add(dp)
+draw.Draw(dst, r, src, sr.Min, draw.Src)
+```
To copy the entire source image, use `sr = src.Bounds()`.
@@ -137,12 +151,14 @@
just as Go's built-in copy function can handle overlapping destination and source slices.
To scroll an image m by 20 pixels:
- b := m.Bounds()
- p := image.Pt(0, 20)
- // Note that even though the second argument is b,
- // the effective rectangle is smaller due to clipping.
- draw.Draw(m, b, m, b.Min.Add(p), draw.Src)
- dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y))
+```go
+b := m.Bounds()
+p := image.Pt(0, 20)
+// Note that even though the second argument is b,
+// the effective rectangle is smaller due to clipping.
+draw.Draw(m, b, m, b.Min.Add(p), draw.Src)
+dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y))
+```
{{image "image-draw/2c.png"}}
@@ -154,9 +170,11 @@
and the result of decoding a PNG depends on the image data.
To convert any image to an `image.RGBA`:
- b := src.Bounds()
- m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
- draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)
+```go
+b := src.Bounds()
+m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
+draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)
+```
{{image "image-draw/2d.png"}}
@@ -165,28 +183,30 @@
To draw an image through a circular mask with center `p` and radius `r`:
{{raw `
- type circle struct {
- p image.Point
- r int
- }
+~~~go
+type circle struct {
+ p image.Point
+ r int
+}
- func (c *circle) ColorModel() color.Model {
- return color.AlphaModel
- }
+func (c *circle) ColorModel() color.Model {
+ return color.AlphaModel
+}
- func (c *circle) Bounds() image.Rectangle {
- return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
- }
+func (c *circle) Bounds() image.Rectangle {
+ return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
+}
- func (c *circle) At(x, y int) color.Color {
- xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
- if xx*xx+yy*yy < rr*rr {
- return color.Alpha{255}
- }
- return color.Alpha{0}
- }
+func (c *circle) At(x, y int) color.Color {
+ xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
+ if xx*xx+yy*yy < rr*rr {
+ return color.Alpha{255}
+ }
+ return color.Alpha{0}
+}
- draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)
+ draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)
+~~~
`}}
{{image "image-draw/2e.png"}}
@@ -198,10 +218,12 @@
For simplicity, we aren't performing any sub-pixel positioning or rendering,
or correcting for a font's height above a baseline.
- src := &image.Uniform{color.RGBA{0, 0, 255, 255}}
- mask := theGlyphImageForAFont()
- mr := theBoundsFor(glyphIndex)
- draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over)
+```go
+src := &image.Uniform{color.RGBA{0, 0, 255, 255}}
+mask := theGlyphImageForAFont()
+mr := theBoundsFor(glyphIndex)
+draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over)
+```
{{image "image-draw/2f.png"}}
diff --git a/_content/blog/image.md b/_content/blog/image.md
index f2f89c2..477afa9 100644
--- a/_content/blog/image.md
+++ b/_content/blog/image.md
@@ -28,13 +28,15 @@
one that can be converted to red, green, blue and alpha values.
The conversion may be lossy, such as converting from CMYK or YCbCr color spaces.
- type Color interface {
- // RGBA returns the alpha-premultiplied red, green, blue and alpha values
- // for the color. Each value ranges within [0, 0xFFFF], but is represented
- // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
- // overflow.
- RGBA() (r, g, b, a uint32)
- }
+```go
+type Color interface {
+ // RGBA returns the alpha-premultiplied red, green, blue and alpha values
+ // for the color. Each value ranges within [0, 0xFFFF], but is represented
+ // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
+ // overflow.
+ RGBA() (r, g, b, a uint32)
+}
+```
There are three important subtleties about the return values.
First, the red, green and blue are alpha-premultiplied:
@@ -49,13 +51,15 @@
in the style of [Porter and Duff's](https://en.wikipedia.org/wiki/Alpha_compositing) classic algebra:
{{raw `
- dstr, dstg, dstb, dsta := dst.RGBA()
- srcr, srcg, srcb, srca := src.RGBA()
- _, _, _, m := mask.RGBA()
- const M = 1<<16 - 1
- // The resultant red value is a blend of dstr and srcr, and ranges in [0, M].
- // The calculation for green, blue and alpha is similar.
- dstr = (dstr*(M-m) + srcr*m) / M
+~~~go
+dstr, dstg, dstb, dsta := dst.RGBA()
+srcr, srcg, srcb, srca := src.RGBA()
+_, _, _, m := mask.RGBA()
+const M = 1<<16 - 1
+// The resultant red value is a blend of dstr and srcr, and ranges in [0, M].
+// The calculation for green, blue and alpha is similar.
+dstr = (dstr*(M-m) + srcr*m) / M
+~~~
`}}
The last line of that code snippet would have been more complicated if we
@@ -67,9 +71,11 @@
For example, [`RGBA`](/pkg/image/color/#RGBA) is a struct
that represents the classic "8 bits per channel" color.
- type RGBA struct {
- R, G, B, A uint8
- }
+```go
+type RGBA struct {
+ R, G, B, A uint8
+}
+```
Note that the `R` field of an `RGBA` is an 8-bit alpha-premultiplied color
in the range [0, 255].
@@ -87,11 +93,13 @@
For example, the `GrayModel` can convert any `Color` to a desaturated [`Gray`](/pkg/image/color/#Gray).
A `Palette` can convert any `Color` to one from a limited palette.
- type Model interface {
- Convert(c Color) Color
- }
+```go
+type Model interface {
+ Convert(c Color) Color
+}
- type Palette []Color
+type Palette []Color
+```
## Points and Rectangles
@@ -100,13 +108,17 @@
It is neither a pixel nor a grid square. A `Point` has no intrinsic width,
height or color, but the visualizations below use a small colored square.
- type Point struct {
- X, Y int
- }
+```go
+type Point struct {
+ X, Y int
+}
+```
{{image "image/image-package-01.png"}}
- p := image.Point{2, 1}
+```go
+p := image.Point{2, 1}
+```
A [`Rectangle`](/pkg/image/#Rectangle) is an axis-aligned
rectangle on the integer grid,
@@ -115,9 +127,11 @@
but the visualizations below outline rectangles with a thin colored line,
and call out their `Min` and `Max` `Point`s.
- type Rectangle struct {
- Min, Max Point
- }
+```go
+type Rectangle struct {
+ Min, Max Point
+}
+```
For convenience, `image.Rect(x0, y0, x1, y1)` is equivalent to `image.Rectangle{image.Point{x0, y0}, image.Point{x1, y1}}`,
but is much easier to type.
@@ -131,25 +145,31 @@
{{image "image/image-package-02.png"}}
- r := image.Rect(2, 1, 5, 5)
- // Dx and Dy return a rectangle's width and height.
- fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 false
+```go
+r := image.Rect(2, 1, 5, 5)
+// Dx and Dy return a rectangle's width and height.
+fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 false
+```
Adding a `Point` to a `Rectangle` translates the `Rectangle`.
Points and Rectangles are not restricted to be in the bottom-right quadrant.
{{image "image/image-package-03.png"}}
- r := image.Rect(2, 1, 5, 5).Add(image.Pt(-4, -2))
- fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 true
+```go
+r := image.Rect(2, 1, 5, 5).Add(image.Pt(-4, -2))
+fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 true
+```
Intersecting two Rectangles yields another Rectangle, which may be empty.
{{image "image/image-package-04.png"}}
- r := image.Rect(0, 0, 4, 3).Intersect(image.Rect(2, 2, 5, 5))
- // Size returns a rectangle's width and height, as a Point.
- fmt.Printf("%#v\n", r.Size()) // prints image.Point{X:2, Y:1}
+```go
+r := image.Rect(0, 0, 4, 3).Intersect(image.Rect(2, 2, 5, 5))
+// Size returns a rectangle's width and height, as a Point.
+fmt.Printf("%#v\n", r.Size()) // prints image.Point{X:2, Y:1}
+```
Points and Rectangles are passed and returned by value.
A function that takes a `Rectangle` argument will be as efficient as a function
@@ -163,17 +183,19 @@
"The pixel at (x, y)" refers to the color of the grid square defined by the points (x,
y), (x+1, y), (x+1, y+1) and (x, y+1).
- type Image interface {
- // ColorModel returns the Image's color model.
- ColorModel() color.Model
- // Bounds returns the domain for which At can return non-zero color.
- // The bounds do not necessarily contain the point (0, 0).
- Bounds() Rectangle
- // At returns the color of the pixel at (x, y).
- // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
- // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
- At(x, y int) color.Color
- }
+```go
+type Image interface {
+ // ColorModel returns the Image's color model.
+ ColorModel() color.Model
+ // Bounds returns the domain for which At can return non-zero color.
+ // The bounds do not necessarily contain the point (0, 0).
+ Bounds() Rectangle
+ // At returns the color of the pixel at (x, y).
+ // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
+ // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
+ At(x, y int) color.Color
+}
+```
A common mistake is assuming that an `Image`'s bounds start at (0, 0).
For example, an animated GIF contains a sequence of Images,
@@ -182,12 +204,14 @@
The correct way to iterate over an `Image` m's pixels looks like:
{{raw `
- b := m.Bounds()
- for y := b.Min.Y; y < b.Max.Y; y++ {
- for x := b.Min.X; x < b.Max.X; x++ {
- doStuffWith(m.At(x, y))
- }
- }
+~~~go
+b := m.Bounds()
+for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ doStuffWith(m.At(x, y))
+ }
+}
+~~~
`}}
`Image` implementations do not have to be based on an in-memory slice of pixel data.
@@ -195,29 +219,35 @@
`Image` of enormous bounds and uniform color,
whose in-memory representation is simply that color.
- type Uniform struct {
- C color.Color
- }
+```go
+type Uniform struct {
+ C color.Color
+}
+```
Typically, though, programs will want an image based on a slice.
Struct types like [`RGBA`](/pkg/image/#RGBA) and [`Gray`](/pkg/image/#Gray)
(which other packages refer to as `image.RGBA` and `image.Gray`) hold slices
of pixel data and implement the `Image` interface.
- type RGBA struct {
- // Pix holds the image's pixels, in R, G, B, A order. The pixel at
- // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
- Pix []uint8
- // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
- Stride int
- // Rect is the image's bounds.
- Rect Rectangle
- }
+```go
+type RGBA struct {
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+```
These types also provide a `Set(x, y int, c color.Color)` method that allows modifying the image one pixel at a time.
- m := image.NewRGBA(image.Rect(0, 0, 640, 480))
- m.Set(5, 5, color.RGBA{255, 0, 0, 255})
+```go
+m := image.NewRGBA(image.Rect(0, 0, 640, 480))
+m.Set(5, 5, color.RGBA{255, 0, 0, 255})
+```
If you're reading or writing a lot of pixel data,
it can be more efficient, but more complicated,
@@ -231,10 +261,12 @@
{{image "image/image-package-05.png"}}
- m0 := image.NewRGBA(image.Rect(0, 0, 8, 5))
- m1 := m0.SubImage(image.Rect(1, 2, 5, 5)).(*image.RGBA)
- fmt.Println(m0.Bounds().Dx(), m1.Bounds().Dx()) // prints 8, 4
- fmt.Println(m0.Stride == m1.Stride) // prints true
+```go
+m0 := image.NewRGBA(image.Rect(0, 0, 8, 5))
+m1 := m0.SubImage(image.Rect(1, 2, 5, 5)).(*image.RGBA)
+fmt.Println(m0.Bounds().Dx(), m1.Bounds().Dx()) // prints 8, 4
+fmt.Println(m0.Stride == m1.Stride) // prints true
+```
For low-level code that works on an image's `Pix` field,
be aware that ranging over `Pix` can affect pixels outside an image's bounds.
@@ -249,20 +281,22 @@
If you know the format of a source image file,
you can decode from an [`io.Reader`](/pkg/io/#Reader) directly.
- import (
- "image/jpeg"
- "image/png"
- "io"
- )
+```go
+import (
+ "image/jpeg"
+ "image/png"
+ "io"
+)
- // convertJPEGToPNG converts from JPEG to PNG.
- func convertJPEGToPNG(w io.Writer, r io.Reader) error {
- img, err := jpeg.Decode(r)
- if err != nil {
- return err
- }
- return png.Encode(w, img)
- }
+// convertJPEGToPNG converts from JPEG to PNG.
+func convertJPEGToPNG(w io.Writer, r io.Reader) error {
+ img, err := jpeg.Decode(r)
+ if err != nil {
+ return err
+ }
+ return png.Encode(w, img)
+}
+```
If you have image data of unknown format,
the [`image.Decode`](/pkg/image/#Decode) function can detect the format.
@@ -272,20 +306,22 @@
and the main package will "underscore import" such a package solely for
the side effect of format registration.
- import (
- "image"
- "image/png"
- "io"
+```go
+import (
+ "image"
+ "image/png"
+ "io"
- _ "code.google.com/p/vp8-go/webp"
- _ "image/jpeg"
- )
+ _ "code.google.com/p/vp8-go/webp"
+ _ "image/jpeg"
+)
- // convertToPNG converts from any recognized format to PNG.
- func convertToPNG(w io.Writer, r io.Reader) error {
- img, _, err := image.Decode(r)
- if err != nil {
- return err
- }
- return png.Encode(w, img)
- }
+// convertToPNG converts from any recognized format to PNG.
+func convertToPNG(w io.Writer, r io.Reader) error {
+ img, _, err := image.Decode(r)
+ if err != nil {
+ return err
+ }
+ return png.Encode(w, img)
+}
+```
diff --git a/_content/blog/inliner.md b/_content/blog/inliner.md
index 7aa54ec..00a6165 100644
--- a/_content/blog/inliner.md
+++ b/_content/blog/inliner.md
@@ -163,7 +163,7 @@
It has several design flaws: the `Sub` function declares its parameters in the wrong order; the `Inf` function implicitly prefers one of the two infinities; and the `Neg` function is redundant with `Sub`. Fortunately we have a `newmath` package that avoids these mistakes, and we’d like to get users to switch to it. The first step is to implement the old API in terms of the new package and to deprecate the old functions. Then we add inliner directives:
-```
+```go
// Package oldmath is the bad old math package.
package oldmath
@@ -194,13 +194,13 @@
Now, when users of `oldmath` run the `go fix` command on their code, it will replace all calls to the old functions by their new counterparts. By the way, gopls has included `inline` in its analyzer suite for some time, so if your editor uses gopls, the moment you add the `//go:fix inline` directives you should start seeing a diagnostic at each call site, such as “call of `oldmath.Sub` should be inlined”, along with a suggested fix that inlines that particular call.
For example, this old code:
-```
+```go
import "oldmath"
var nine = oldmath.Sub(1, 10) // diagnostic: "call to oldmath.Sub should be inlined"
```
will be transformed to:
-```
+```go
import "newmath"
var nine = newmath.Sub(10, 1)
@@ -208,7 +208,7 @@
Observe that after the fix, the arguments to `Sub` are in the logical order. This is progress! If you’re in luck, the inliner will succeed at removing every call to the functions in `oldmath`, perhaps allowing you to delete it as a dependency.
The `inline` analyzer works on types and constants too. If our `oldmath` package had originally declared a data type for rational numbers and a constant for π, we could use the following forwarding declarations to migrate them to the `newmath` package while preserving the behavior of existing code:
-```
+```go
package oldmath
//go:fix inline
@@ -235,17 +235,17 @@
One of the inliner’s most important tasks is to attempt to replace each occurrence of a parameter in the callee by its corresponding argument from the call. In the simplest case, the argument is a trivial literal such as `0` or `""`, so the replacement is straightforward and the parameter can be eliminated.
<div class="beforeafter">
-<div class="beforeafter-context"><pre>
+<div class="beforeafter-context"><pre lang=go>
//go:fix inline
func show(prefix, item string) {
fmt.Println(prefix, item)
}
</pre></div>
-<pre>
+<pre lang=go>
show("", "hello")
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
fmt.Println("", "hello")
</pre>
</div>
@@ -255,18 +255,18 @@
In such cases the inliner must tread carefully and emit a more conservative result. Whenever one or more parameters cannot be completely substituted for any reason, the inliner inserts an explicit “parameter binding” declaration:
<div class="beforeafter">
-<div class="beforeafter-context"><pre>
+<div class="beforeafter-context"><pre lang=go>
//go:fix inline
func printPair(before, x, y, after string) {
fmt.Println(before, x, after)
fmt.Println(before, y, after)
}
</pre></div>
-<pre>
+<pre lang=go>
printPair("[", "one", "two", "]")
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
// a “parameter binding” declaration
var before, after = "[", "]"
fmt.Println(before, "one", after)
@@ -286,7 +286,7 @@
A trivial inlining of the call would replace `x` with `f()` and `y` with `g()`, with this result:
-```
+```go
z = g() + f()
```
@@ -294,7 +294,7 @@
So, the inliner must attempt to prove that `f()` and `g()` do not have side effects on each other. On success, it can safely proceed with the result above. Otherwise, it must fall back to an explicit parameter binding:
-```
+```go
var x = f()
z = g() + x
```
@@ -314,7 +314,7 @@
The inliner uses a novel [hazard analysis](https://cs.opensource.google/go/x/tools/+/refs/tags/v0.42.0:internal/refactor/inline/inline.go;l=1978;drc=e3a69ffcdbb984f50100e76ebca6ff53cf88de9c) to model the order of effects in each callee function. Nonetheless, its ability to construct the necessary safety proofs is quite limited. For example, if the calls `f()` and `g()` are simple accessors, it would be perfectly safe to call them in either order. Indeed, an optimizing compiler might use its knowledge of the internals of `f` and `g` to safely reorder the two calls. But unlike a compiler, which generates object code that reflects the source at a specific moment, the purpose of the inliner is to make permanent changes to the source, so it can’t take advantage of ephemeral details. As an extreme example, consider this `start` function:
-```
+```go
func start() { /* TODO: implement */ }
```
@@ -328,7 +328,7 @@
You might imagine (as I once did) that it would always be safe to replace a parameter variable by a constant argument of the same type. Surprisingly, this turns out not to be the case, because some checks previously done at run time would now happen—and fail—at compile time. Consider this call to the `index` function:
-```
+```go
//go:fix inline
func index(s string, i int) byte {
return s[i]
@@ -353,19 +353,19 @@
Typical argument expressions contain one or more identifiers that refer to symbols (variables, functions, and so on) in the caller’s file. The inliner must make sure that each name in the argument expression would refer to the same symbol after parameter substitution; in other words, none of the caller’s names is *shadowed* in the callee. If this fails, the inliner must again insert parameter bindings, as in this example:
<div class="beforeafter">
-<div class="beforeafter-context"><pre>
+<div class="beforeafter-context"><pre lang=go>
//go:fix inline
func f(val string) {
x := 123
fmt.Println(val, x)
}
</pre></div>
-<pre>
+<pre lang=go>
x := "hello"
f(x)
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
x := "hello"
{
// another “parameter binding” declaration
@@ -384,16 +384,16 @@
When an argument expression has no effects and its corresponding parameter is never used, the expression may be eliminated. However, if the expression contains the last reference to a local variable at the caller, this may cause a compile error because the variable is now unused.
<div class="beforeafter">
-<div class="beforeafter-context"><pre>
+<div class="beforeafter-context"><pre lang=go>
//go:fix inline
func f(_ int) { print("hello") }
</pre></div>
-<pre>
+<pre lang=go>
x := 42
f(x)
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
x := 42 // error: unused variable: x
print("hello")
</pre>
@@ -413,18 +413,18 @@
`defer` statement, as in this example:
<div class="beforeafter">
-<div class="beforeafter-context"><pre>
+<div class="beforeafter-context"><pre lang=go>
//go:fix inline
func callee() {
defer f()
…
}
</pre></div>
-<pre>
+<pre lang=go>
callee()
</pre>
<div class="beforeafter-arrow"></div>
-<pre>
+<pre lang=go>
func() {
defer f()
…
diff --git a/_content/blog/intro-generics.md b/_content/blog/intro-generics.md
index c993faa..d4d5c1a 100644
--- a/_content/blog/intro-generics.md
+++ b/_content/blog/intro-generics.md
@@ -53,12 +53,14 @@
function for floating point values:
{{raw `
- func Min(x, y float64) float64 {
- if x < y {
- return x
- }
- return y
+~~~go
+func Min(x, y float64) float64 {
+ if x < y {
+ return x
}
+ return y
+}
+~~~
`}}
We can make this function generic--make it work for different
@@ -67,21 +69,25 @@
parameter `T`, and replace the uses of `float64` with `T`.
{{raw `
- import "golang.org/x/exp/constraints"
+~~~go
+import "golang.org/x/exp/constraints"
- func GMin[T constraints.Ordered](x, y T) T {
- if x < y {
- return x
- }
- return y
+func GMin[T constraints.Ordered](x, y T) T {
+ if x < y {
+ return x
}
+ return y
+}
+~~~
`}}
It is now possible to call this function with a type argument by
writing a call like
{{raw `
- x := GMin[int](2, 3)
+~~~go
+x := GMin[int](2, 3)
+~~~
`}}
Providing the type argument to `GMin`, in this case `int`, is called
@@ -99,8 +105,10 @@
For example, in code like
{{raw `
- fmin := GMin[float64]
- m := fmin(2.71, 3.14)
+~~~go
+fmin := GMin[float64]
+m := fmin(2.71, 3.14)
+~~~
`}}
the instantiation `GMin[float64]` produces what is effectively our
@@ -110,14 +118,16 @@
Type parameters can be used with types also.
{{raw `
- type Tree[T interface{}] struct {
- left, right *Tree[T]
- value T
- }
+~~~go
+type Tree[T interface{}] struct {
+ left, right *Tree[T]
+ value T
+}
- func (t *Tree[T]) Lookup(x T) *Tree[T] { ... }
+func (t *Tree[T]) Lookup(x T) *Tree[T] { ... }
- var stringTree Tree[string]
+var stringTree Tree[string]
+~~~
`}}
Here the generic type `Tree` stores values of the type parameter `T`.
@@ -196,9 +206,11 @@
Now let's look at the actual definition of `constraints.Ordered`:
{{raw `
- type Ordered interface {
- Integer|Float|~string
- }
+~~~go
+type Ordered interface {
+ Integer|Float|~string
+}
+~~~
`}}
This declaration says that the `Ordered` interface is the set of all
@@ -237,7 +249,9 @@
For example:
{{raw `
- [S interface{~[]E}, E interface{}]
+~~~go
+[S interface{~[]E}, E interface{}]
+~~~
`}}
Here `S` must be a slice type whose element type can be any type.
@@ -247,7 +261,9 @@
write:
{{raw `
- [S ~[]E, E interface{}]
+~~~go
+[S ~[]E, E interface{}]
+~~~
`}}
Because the empty interface is common in type parameter lists, and in
@@ -256,7 +272,9 @@
With that, we arrive at this idiomatic code:
{{raw `
- [S ~[]E, E any]
+~~~go
+[S ~[]E, E any]
+~~~
`}}
Interfaces as type sets is a powerful new mechanism and is key to
@@ -280,7 +298,9 @@
Going back to our generic `GMin` function:
{{raw `
- func GMin[T constraints.Ordered](x, y T) T { ... }
+~~~go
+func GMin[T constraints.Ordered](x, y T) T { ... }
+~~~
`}}
the type parameter `T` is used to specify the types of the ordinary
@@ -288,9 +308,11 @@
As we saw earlier, this can be called with an explicit type argument
{{raw `
- var a, b, m float64
+~~~go
+var a, b, m float64
- m = GMin[float64](a, b) // explicit type argument
+m = GMin[float64](a, b) // explicit type argument
+~~~
`}}
In many cases the compiler can infer the type argument for `T` from
@@ -298,9 +320,11 @@
This makes the code shorter while remaining clear.
{{raw `
- var a, b, m float64
+~~~go
+var a, b, m float64
- m = GMin(a, b) // no type argument
+m = GMin(a, b) // no type argument
+~~~
`}}
This works by matching the types of the arguments `a` and `b` with the
@@ -324,15 +348,17 @@
integers:
{{raw `
- // Scale returns a copy of s with each element multiplied by c.
- // This implementation has a problem, as we will see.
- func Scale[E constraints.Integer](s []E, c E) []E {
- r := make([]E, len(s))
- for i, v := range s {
- r[i] = v * c
- }
- return r
+~~~go
+// Scale returns a copy of s with each element multiplied by c.
+// This implementation has a problem, as we will see.
+func Scale[E constraints.Integer](s []E, c E) []E {
+ r := make([]E, len(s))
+ for i, v := range s {
+ r[i] = v * c
}
+ return r
+}
+~~~
`}}
This is a generic function that works for a slice of any integer
@@ -344,11 +370,13 @@
Naturally this type will have some methods.
{{raw `
- type Point []int32
+~~~go
+type Point []int32
- func (p Point) String() string {
- // Details not important.
- }
+func (p Point) String() string {
+ // Details not important.
+}
+~~~
`}}
Sometimes we want to scale a `Point`.
@@ -356,11 +384,13 @@
function we wrote earlier:
{{raw `
- // ScaleAndPrint doubles a Point and prints it.
- func ScaleAndPrint(p Point) {
- r := Scale(p, 2)
- fmt.Println(r.String()) // DOES NOT COMPILE
- }
+~~~go
+// ScaleAndPrint doubles a Point and prints it.
+func ScaleAndPrint(p Point) {
+ r := Scale(p, 2)
+ fmt.Println(r.String()) // DOES NOT COMPILE
+}
+~~~
`}}
Unfortunately this does not compile, failing with an error like
@@ -378,14 +408,16 @@
type parameter for the slice type.
{{raw `
- // Scale returns a copy of s with each element multiplied by c.
- func Scale[S ~[]E, E constraints.Integer](s S, c E) S {
- r := make(S, len(s))
- for i, v := range s {
- r[i] = v * c
- }
- return r
+~~~go
+// Scale returns a copy of s with each element multiplied by c.
+func Scale[S ~[]E, E constraints.Integer](s S, c E) S {
+ r := make(S, len(s))
+ for i, v := range s {
+ r[i] = v * c
}
+ return r
+}
+~~~
`}}
We've introduced a new type parameter `S` that is the type of the
diff --git a/_content/blog/introducing-gofix.md b/_content/blog/introducing-gofix.md
index a86e85e..3ab2b27 100644
--- a/_content/blog/introducing-gofix.md
+++ b/_content/blog/introducing-gofix.md
@@ -64,35 +64,39 @@
As an example, gofix can rewrite code like [this snippet from `fmt/print.go`](http://codereview.appspot.com/4353043/diff/10001/src/pkg/fmt/print.go#newcode657):
- switch f := value.(type) {
- case *reflect.BoolValue:
- p.fmtBool(f.Get(), verb, field)
- case *reflect.IntValue:
- p.fmtInt64(f.Get(), verb, field)
- // ...
- case reflect.ArrayOrSliceValue:
- // Byte slices are special.
- if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
- // ...
- }
- // ...
- }
+```go
+switch f := value.(type) {
+case *reflect.BoolValue:
+ p.fmtBool(f.Get(), verb, field)
+case *reflect.IntValue:
+ p.fmtInt64(f.Get(), verb, field)
+// ...
+case reflect.ArrayOrSliceValue:
+ // Byte slices are special.
+ if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
+ // ...
+ }
+// ...
+}
+```
to adapt it to the new reflect API:
- switch f := value; f.Kind() {
- case reflect.Bool:
- p.fmtBool(f.Bool(), verb, field)
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, field)
- // ...
- case reflect.Array, reflect.Slice:
- // Byte slices are special.
- if f.Type().Elem().Kind() == reflect.Uint8 {
- // ...
- }
- // ...
- }
+```go
+switch f := value; f.Kind() {
+case reflect.Bool:
+ p.fmtBool(f.Bool(), verb, field)
+case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.fmtInt64(f.Int(), verb, field)
+// ...
+case reflect.Array, reflect.Slice:
+ // Byte slices are special.
+ if f.Type().Elem().Kind() == reflect.Uint8 {
+ // ...
+ }
+// ...
+}
+```
Nearly every line above changed in some small way.
The changes involved in the rewrite are extensive but nearly entirely mechanical,
diff --git a/_content/blog/json-rpc.md b/_content/blog/json-rpc.md
index b943901..74725de 100644
--- a/_content/blog/json-rpc.md
+++ b/_content/blog/json-rpc.md
@@ -22,23 +22,29 @@
existing wire format,
one for the client, and one for the server (depicted below).
- type ServerCodec interface {
- ReadRequestHeader(*Request) error
- ReadRequestBody(interface{}) error
- WriteResponse(*Response, interface{}) error
- Close() error
- }
+```go
+type ServerCodec interface {
+ ReadRequestHeader(*Request) error
+ ReadRequestBody(interface{}) error
+ WriteResponse(*Response, interface{}) error
+ Close() error
+}
+```
On the server side, we then changed two internal function signatures to
accept the `ServerCodec` interface instead of our existing `gob.Encoder`. Here's one of them:
- func sendResponse(sending *sync.Mutex, req *Request,
- reply interface{}, enc *gob.Encoder, errmsg string)
+```go
+func sendResponse(sending *sync.Mutex, req *Request,
+ reply interface{}, enc *gob.Encoder, errmsg string)
+```
became
- func sendResponse(sending *sync.Mutex, req *Request,
- reply interface{}, enc ServerCodec, errmsg string)
+```go
+func sendResponse(sending *sync.Mutex, req *Request,
+ reply interface{}, enc ServerCodec, errmsg string)
+```
We then wrote a trivial `gobServerCodec` wrapper to reproduce the original functionality.
From there it is simple to build a `jsonServerCodec`.
diff --git a/_content/blog/json.md b/_content/blog/json.md
index 4ddad90..1719572 100644
--- a/_content/blog/json.md
+++ b/_content/blog/json.md
@@ -29,27 +29,37 @@
To encode JSON data we use the [`Marshal`](/pkg/encoding/json/#Marshal) function.
- func Marshal(v interface{}) ([]byte, error)
+```go
+func Marshal(v interface{}) ([]byte, error)
+```
Given the Go data structure, `Message`,
- type Message struct {
- Name string
- Body string
- Time int64
- }
+```go
+type Message struct {
+ Name string
+ Body string
+ Time int64
+}
+```
and an instance of `Message`
- m := Message{"Alice", "Hello", 1294706395881547000}
+```go
+m := Message{"Alice", "Hello", 1294706395881547000}
+```
we can marshal a JSON-encoded version of m using `json.Marshal`:
- b, err := json.Marshal(m)
+```go
+b, err := json.Marshal(m)
+```
If all is well, `err` will be `nil` and `b` will be a `[]byte` containing this JSON data:
- b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
+```go
+b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
+```
Only data structures that can be represented as valid JSON will be encoded:
@@ -71,26 +81,34 @@
To decode JSON data we use the [`Unmarshal`](/pkg/encoding/json/#Unmarshal) function.
- func Unmarshal(data []byte, v interface{}) error
+```go
+func Unmarshal(data []byte, v interface{}) error
+```
We must first create a place where the decoded data will be stored
- var m Message
+```go
+var m Message
+```
and call `json.Unmarshal`, passing it a `[]byte` of JSON data and a pointer to `m`
- err := json.Unmarshal(b, &m)
+```go
+err := json.Unmarshal(b, &m)
+```
If `b` contains valid JSON that fits in `m`,
after the call `err` will be `nil` and the data from `b` will have been
stored in the struct `m`,
as if by an assignment like:
- m = Message{
- Name: "Alice",
- Body: "Hello",
- Time: 1294706395881547000,
- }
+```go
+m = Message{
+ Name: "Alice",
+ Body: "Hello",
+ Time: 1294706395881547000,
+}
+```
How does `Unmarshal` identify the fields in which to store the decoded data?
For a given JSON key `"Foo"`,
@@ -106,9 +124,11 @@
What happens when the structure of the JSON data doesn't exactly match the Go type?
- b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
- var m Message
- err := json.Unmarshal(b, &m)
+```go
+b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
+var m Message
+err := json.Unmarshal(b, &m)
+```
`Unmarshal` will decode only the fields that it can find in the destination type.
In this case, only the Name field of m will be populated,
@@ -127,29 +147,35 @@
The empty interface serves as a general container type:
- var i interface{}
- i = "a string"
- i = 2011
- i = 2.777
+```go
+var i interface{}
+i = "a string"
+i = 2011
+i = 2.777
+```
A type assertion accesses the underlying concrete type:
- r := i.(float64)
- fmt.Println("the circle's area", math.Pi*r*r)
+```go
+r := i.(float64)
+fmt.Println("the circle's area", math.Pi*r*r)
+```
Or, if the underlying type is unknown, a type switch determines the type:
- switch v := i.(type) {
- case int:
- fmt.Println("twice i is", v*2)
- case float64:
- fmt.Println("the reciprocal of i is", 1/v)
- case string:
- h := len(v) / 2
- fmt.Println("i swapped by halves is", v[h:]+v[:h])
- default:
- // i isn't one of the types above
- }
+```go
+switch v := i.(type) {
+case int:
+ fmt.Println("twice i is", v*2)
+case float64:
+ fmt.Println("the reciprocal of i is", 1/v)
+case string:
+ h := len(v) / 2
+ fmt.Println("i swapped by halves is", v[h:]+v[:h])
+default:
+ // i isn't one of the types above
+}
+```
The json package uses `map[string]interface{}` and
`[]interface{}` values to store arbitrary JSON objects and arrays;
@@ -168,47 +194,57 @@
Consider this JSON data, stored in the variable `b`:
- b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
+```go
+b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
+```
Without knowing this data's structure, we can decode it into an `interface{}` value with `Unmarshal`:
- var f interface{}
- err := json.Unmarshal(b, &f)
+```go
+var f interface{}
+err := json.Unmarshal(b, &f)
+```
At this point the Go value in `f` would be a map whose keys are strings
and whose values are themselves stored as empty interface values:
- f = map[string]interface{}{
- "Name": "Wednesday",
- "Age": 6,
- "Parents": []interface{}{
- "Gomez",
- "Morticia",
- },
- }
+```go
+f = map[string]interface{}{
+ "Name": "Wednesday",
+ "Age": 6,
+ "Parents": []interface{}{
+ "Gomez",
+ "Morticia",
+ },
+}
+```
To access this data we can use a type assertion to access `f`'s underlying `map[string]interface{}`:
- m := f.(map[string]interface{})
+```go
+m := f.(map[string]interface{})
+```
We can then iterate through the map with a range statement and use a type
switch to access its values as their concrete types:
- for k, v := range m {
- switch vv := v.(type) {
- case string:
- fmt.Println(k, "is string", vv)
- case float64:
- fmt.Println(k, "is float64", vv)
- case []interface{}:
- fmt.Println(k, "is an array:")
- for i, u := range vv {
- fmt.Println(i, u)
- }
- default:
- fmt.Println(k, "is of a type I don't know how to handle")
- }
- }
+```go
+for k, v := range m {
+ switch vv := v.(type) {
+ case string:
+ fmt.Println(k, "is string", vv)
+ case float64:
+ fmt.Println(k, "is float64", vv)
+ case []interface{}:
+ fmt.Println(k, "is an array:")
+ for i, u := range vv {
+ fmt.Println(i, u)
+ }
+ default:
+ fmt.Println(k, "is of a type I don't know how to handle")
+ }
+}
+```
In this way you can work with unknown JSON data while still enjoying the benefits of type safety.
@@ -216,14 +252,16 @@
Let's define a Go type to contain the data from the previous example:
- type FamilyMember struct {
- Name string
- Age int
- Parents []string
- }
+```go
+type FamilyMember struct {
+ Name string
+ Age int
+ Parents []string
+}
- var m FamilyMember
- err := json.Unmarshal(b, &m)
+var m FamilyMember
+err := json.Unmarshal(b, &m)
+```
Unmarshaling that data into a `FamilyMember` value works as expected,
but if we look closely we can see a remarkable thing has happened.
@@ -236,9 +274,11 @@
Consider unmarshaling into this data structure:
- type Foo struct {
- Bar *Bar
- }
+```go
+type Foo struct {
+ Bar *Bar
+}
+```
If there were a `Bar` field in the JSON object,
`Unmarshal` would allocate a new `Bar` and populate it.
@@ -248,10 +288,12 @@
a few distinct message types,
you might define "receiver" structure like
- type IncomingMessage struct {
- Cmd *Command
- Msg *Message
- }
+```go
+type IncomingMessage struct {
+ Cmd *Command
+ Msg *Message
+}
+```
and the sending party can populate the `Cmd` field and/or the `Msg` field
of the top-level JSON object,
@@ -268,40 +310,44 @@
The `NewDecoder` and `NewEncoder` functions wrap the [`io.Reader`](/pkg/io/#Reader)
and [`io.Writer`](/pkg/io/#Writer) interface types.
- func NewDecoder(r io.Reader) *Decoder
- func NewEncoder(w io.Writer) *Encoder
+```go
+func NewDecoder(r io.Reader) *Decoder
+func NewEncoder(w io.Writer) *Encoder
+```
Here's an example program that reads a series of JSON objects from standard input,
removes all but the `Name` field from each object,
and then writes the objects to standard output:
- package main
+```go
+package main
- import (
- "encoding/json"
- "log"
- "os"
- )
+import (
+ "encoding/json"
+ "log"
+ "os"
+)
- func main() {
- dec := json.NewDecoder(os.Stdin)
- enc := json.NewEncoder(os.Stdout)
- for {
- var v map[string]interface{}
- if err := dec.Decode(&v); err != nil {
- log.Println(err)
- return
- }
- for k := range v {
- if k != "Name" {
- delete(v, k)
- }
- }
- if err := enc.Encode(&v); err != nil {
- log.Println(err)
- }
- }
- }
+func main() {
+ dec := json.NewDecoder(os.Stdin)
+ enc := json.NewEncoder(os.Stdout)
+ for {
+ var v map[string]interface{}
+ if err := dec.Decode(&v); err != nil {
+ log.Println(err)
+ return
+ }
+ for k := range v {
+ if k != "Name" {
+ delete(v, k)
+ }
+ }
+ if err := enc.Encode(&v); err != nil {
+ log.Println(err)
+ }
+ }
+}
+```
Due to the ubiquity of Readers and Writers,
these `Encoder` and `Decoder` types can be used in a broad range of scenarios,
diff --git a/_content/blog/jsonv2-exp.md b/_content/blog/jsonv2-exp.md
index 81e9dc0..ac7e08c 100644
--- a/_content/blog/jsonv2-exp.md
+++ b/_content/blog/jsonv2-exp.md
@@ -216,7 +216,7 @@
The basic API of `jsontext` is the following:
-```
+```go
package jsontext
type Encoder struct { ... }
@@ -287,7 +287,7 @@
read [Anton Zhiyanov's blog covering the topic](https://antonz.org/go-json-v2/).
The basic API of `v2` is the following:
-```
+```go
package json
func Marshal(in any, opts ...Options) (out []byte, err error)
@@ -321,7 +321,7 @@
Similar to `v1`, `v2` allows types to define their own JSON representation
by satisfying particular interfaces.
-```
+```go
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
@@ -356,7 +356,7 @@
where caller-specified functions take precedence over type-defined methods
or the default representation for a particular type.
-```
+```go
func WithMarshalers(*Marshalers) Options
type Marshalers struct { ... }
diff --git a/_content/blog/laws-of-reflection.md b/_content/blog/laws-of-reflection.md
index 4cf2edb..e3d6517 100644
--- a/_content/blog/laws-of-reflection.md
+++ b/_content/blog/laws-of-reflection.md
@@ -39,10 +39,12 @@
that is, exactly one type known and fixed at compile time:
`int`, `float32`, `*MyType`, `[]byte`, and so on. If we declare
- type MyInt int
+```go
+type MyInt int
- var i int
- var j MyInt
+var i int
+var j MyInt
+```
then `i` has type `int` and `j` has type `MyInt`.
The variables `i` and `j` have distinct static types and,
@@ -58,26 +60,30 @@
A well-known pair of examples is `io.Reader` and `io.Writer`,
the types `Reader` and `Writer` from the [io package](/pkg/io/):
- // Reader is the interface that wraps the basic Read method.
- type Reader interface {
- Read(p []byte) (n int, err error)
- }
+```go
+// Reader is the interface that wraps the basic Read method.
+type Reader interface {
+ Read(p []byte) (n int, err error)
+}
- // Writer is the interface that wraps the basic Write method.
- type Writer interface {
- Write(p []byte) (n int, err error)
- }
+// Writer is the interface that wraps the basic Write method.
+type Writer interface {
+ Write(p []byte) (n int, err error)
+}
+```
Any type that implements a `Read` (or `Write`) method with this signature
is said to implement `io.Reader` (or `io.Writer`).
For the purposes of this discussion, that means that a variable of type
`io.Reader` can hold any value whose type has a `Read` method:
- var r io.Reader
- r = os.Stdin
- r = bufio.NewReader(r)
- r = new(bytes.Buffer)
- // and so on
+```go
+var r io.Reader
+r = os.Stdin
+r = bufio.NewReader(r)
+r = new(bytes.Buffer)
+// and so on
+```
It's important to be clear that whatever concrete value `r` may hold,
`r`'s type is always `io.Reader`:
@@ -85,11 +91,15 @@
An extremely important example of an interface type is the empty interface:
- interface{}
+```go
+interface{}
+```
or its equivalent alias,
- any
+```go
+any
+```
It represents the empty set of methods and is satisfied by any value at all, since every value has zero or more methods.
@@ -114,12 +124,14 @@
To be more precise, the value is the underlying concrete data item that
implements the interface and the type describes the full type of that item. For instance, after
- var r io.Reader
- tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
- if err != nil {
- return nil, err
- }
- r = tty
+```go
+var r io.Reader
+tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
+if err != nil {
+ return nil, err
+}
+r = tty
+```
`r` contains, schematically, the (value, type) pair,
(`tty`, `*os.File`).
@@ -128,8 +140,10 @@
the value inside carries all the type information about that value.
That's why we can do things like this:
- var w io.Writer
- w = r.(io.Writer)
+```go
+var w io.Writer
+w = r.(io.Writer)
+```
The expression in this assignment is a type assertion;
what it asserts is that the item inside `r` also implements `io.Writer`,
@@ -141,8 +155,10 @@
Continuing, we can do this:
- var empty interface{}
- empty = w
+```go
+var empty interface{}
+empty = w
+```
and our empty interface value `empty` will again contain that same pair,
(`tty`, `*os.File`).
@@ -177,17 +193,19 @@
Let's start with `TypeOf`:
- package main
+```go
+package main
- import (
- "fmt"
- "reflect"
- )
+import (
+ "fmt"
+ "reflect"
+)
- func main() {
- var x float64 = 3.4
- fmt.Println("type:", reflect.TypeOf(x))
- }
+func main() {
+ var x float64 = 3.4
+ fmt.Println("type:", reflect.TypeOf(x))
+}
+```
This program prints
@@ -199,8 +217,10 @@
But it's there; as [godoc reports](/pkg/reflect/#TypeOf),
the signature of `reflect.TypeOf` includes an empty interface:
- // TypeOf returns the reflection Type of the value in the interface{}.
- func TypeOf(i interface{}) Type
+```go
+// TypeOf returns the reflection Type of the value in the interface{}.
+func TypeOf(i interface{}) Type
+```
When we call `reflect.TypeOf(x)`, `x` is first stored in an empty interface,
which is then passed as the argument;
@@ -210,8 +230,10 @@
recovers the value (from here on we'll elide the boilerplate and focus just
on the executable code):
- var x float64 = 3.4
- fmt.Println("value:", reflect.ValueOf(x).String())
+```go
+var x float64 = 3.4
+fmt.Println("value:", reflect.ValueOf(x).String())
+```
prints
@@ -233,11 +255,13 @@
Also methods on `Value` with names like `Int` and `Float` let us grab values
(as `int64` and `float64`) stored inside:
- var x float64 = 3.4
- v := reflect.ValueOf(x)
- fmt.Println("type:", v.Type())
- fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
- fmt.Println("value:", v.Float())
+```go
+var x float64 = 3.4
+v := reflect.ValueOf(x)
+fmt.Println("type:", v.Type())
+fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
+fmt.Println("value:", v.Float())
+```
prints
@@ -257,20 +281,24 @@
value takes an `int64`;
it may be necessary to convert to the actual type involved:
- var x uint8 = 'x'
- v := reflect.ValueOf(x)
- fmt.Println("type:", v.Type()) // uint8.
- fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
- x = uint8(v.Uint()) // v.Uint returns a uint64.
+```go
+var x uint8 = 'x'
+v := reflect.ValueOf(x)
+fmt.Println("type:", v.Type()) // uint8.
+fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
+x = uint8(v.Uint()) // v.Uint returns a uint64.
+```
The second property is that the `Kind` of a reflection object describes
the underlying type,
not the static type.
If a reflection object contains a value of a user-defined integer type, as in
- type MyInt int
- var x MyInt = 7
- v := reflect.ValueOf(x)
+```go
+type MyInt int
+var x MyInt = 7
+v := reflect.ValueOf(x)
+```
the `Kind` of `v` is still `reflect.Int`,
even though the static type of `x` is `MyInt`, not `int`.
@@ -287,13 +315,17 @@
in effect the method packs the type and value information back into an interface
representation and returns the result:
- // Interface returns v's value as an interface{}.
- func (v Value) Interface() interface{}
+```go
+// Interface returns v's value as an interface{}.
+func (v Value) Interface() interface{}
+```
As a consequence we can say
- y := v.Interface().(float64) // y will have type float64.
- fmt.Println(y)
+```go
+y := v.Interface().(float64) // y will have type float64.
+fmt.Println(y)
+```
to print the `float64` value represented by the reflection object `v`.
@@ -304,13 +336,17 @@
Therefore all it takes to print the contents of a `reflect.Value` correctly
is to pass the result of the `Interface` method to the formatted print routine:
- fmt.Println(v.Interface())
+```go
+fmt.Println(v.Interface())
+```
(Since this article was first written, a change was made to the `fmt`
package so that it automatically unpacks a `reflect.Value` like this, so
we could just say
- fmt.Println(v)
+```go
+fmt.Println(v)
+```
for the same result, but for clarity we'll keep the `.Interface()` calls
here.)
@@ -318,7 +354,9 @@
Since our value is a `float64`,
we can even use a floating-point format if we want:
- fmt.Printf("value is %7.1e\n", v.Interface())
+```go
+fmt.Printf("value is %7.1e\n", v.Interface())
+```
and get in this case
@@ -341,9 +379,11 @@
Here is some code that does not work, but is worth studying.
- var x float64 = 3.4
- v := reflect.ValueOf(x)
- v.SetFloat(7.1) // Error: will panic.
+```go
+var x float64 = 3.4
+v := reflect.ValueOf(x)
+v.SetFloat(7.1) // Error: will panic.
+```
If you run this code, it will panic with the cryptic message
@@ -356,9 +396,11 @@
The `CanSet` method of `Value` reports the settability of a `Value`; in our case,
- var x float64 = 3.4
- v := reflect.ValueOf(x)
- fmt.Println("settability of v:", v.CanSet())
+```go
+var x float64 = 3.4
+v := reflect.ValueOf(x)
+fmt.Println("settability of v:", v.CanSet())
+```
prints
@@ -371,15 +413,19 @@
that was used to create the reflection object.
Settability is determined by whether the reflection object holds the original item. When we say
- var x float64 = 3.4
- v := reflect.ValueOf(x)
+```go
+var x float64 = 3.4
+v := reflect.ValueOf(x)
+```
we pass a copy of `x` to `reflect.ValueOf`,
so the interface value created as the argument to `reflect.ValueOf` is a
copy of `x`, not `x` itself.
Thus, if the statement
- v.SetFloat(7.1)
+```go
+v.SetFloat(7.1)
+```
were allowed to succeed, it would not update `x`,
even though `v` looks like it was created from `x`.
@@ -391,14 +437,18 @@
If this seems bizarre, it's not. It's actually a familiar situation in unusual garb.
Think of passing `x` to a function:
- f(x)
+```go
+f(x)
+```
We would not expect `f` to be able to modify `x` because we passed a copy
of `x`'s value, not `x` itself.
If we want `f` to modify `x` directly we must pass our function the address
of `x` (that is, a pointer to `x`):
- f(&x)
+```go
+f(&x)
+```
This is straightforward and familiar, and reflection works the same way.
If we want to modify `x` by reflection, we must give the reflection library
@@ -406,10 +456,12 @@
Let's do that. First we initialize `x` as usual and then create a reflection value that points to it, called `p`.
- var x float64 = 3.4
- p := reflect.ValueOf(&x) // Note: take the address of x.
- fmt.Println("type of p:", p.Type())
- fmt.Println("settability of p:", p.CanSet())
+```go
+var x float64 = 3.4
+p := reflect.ValueOf(&x) // Note: take the address of x.
+fmt.Println("type of p:", p.Type())
+fmt.Println("settability of p:", p.CanSet())
+```
The output so far is
@@ -421,8 +473,10 @@
To get to what `p` points to, we call the `Elem` method of `Value`,
which indirects through the pointer, and save the result in a reflection `Value` called `v`:
- v := p.Elem()
- fmt.Println("settability of v:", v.CanSet())
+```go
+v := p.Elem()
+fmt.Println("settability of v:", v.CanSet())
+```
Now `v` is a settable reflection object, as the output demonstrates,
@@ -430,9 +484,11 @@
and since it represents `x`, we are finally able to use `v.SetFloat` to modify the value of `x`:
- v.SetFloat(7.1)
- fmt.Println(v.Interface())
- fmt.Println(x)
+```go
+v.SetFloat(7.1)
+fmt.Println(v.Interface())
+fmt.Println(x)
+```
The output, as expected, is
@@ -462,18 +518,20 @@
but the fields themselves are regular `reflect.Value` objects.
{{raw `
- type T struct {
- A int
- B string
- }
- t := T{23, "skidoo"}
- s := reflect.ValueOf(&t).Elem()
- typeOfT := s.Type()
- for i := 0; i < s.NumField(); i++ {
- f := s.Field(i)
- fmt.Printf("%d: %s %s = %v\n", i,
- typeOfT.Field(i).Name, f.Type(), f.Interface())
- }
+~~~go
+type T struct {
+ A int
+ B string
+}
+t := T{23, "skidoo"}
+s := reflect.ValueOf(&t).Elem()
+typeOfT := s.Type()
+for i := 0; i < s.NumField(); i++ {
+ f := s.Field(i)
+ fmt.Printf("%d: %s %s = %v\n", i,
+ typeOfT.Field(i).Name, f.Type(), f.Interface())
+}
+~~~
`}}
The output of this program is
@@ -487,9 +545,11 @@
Because `s` contains a settable reflection object, we can modify the fields of the structure.
- s.Field(0).SetInt(77)
- s.Field(1).SetString("Sunset Strip")
- fmt.Println("t is now", t)
+```go
+s.Field(0).SetInt(77)
+s.Field(1).SetString("Sunset Strip")
+fmt.Println("t is now", t)
+```
And here's the result:
diff --git a/_content/blog/llmpowered.md b/_content/blog/llmpowered.md
index dee9f99..cd8e12f 100644
--- a/_content/blog/llmpowered.md
+++ b/_content/blog/llmpowered.md
@@ -119,7 +119,7 @@
using the [routing enhancements](/blog/routing-enhancements) introduced in
Go 1.22:
-```Go
+```go
mux := http.NewServeMux()
mux.HandleFunc("POST /add/", server.addDocumentsHandler)
mux.HandleFunc("POST /query/", server.queryHandler)
@@ -163,7 +163,7 @@
just a few lines of code in our server, since all the DBs implement a
[common interface](https://pkg.go.dev/github.com/tmc/langchaingo@v0.1.12/vectorstores#VectorStore):
-```Go
+```go
type VectorStore interface {
AddDocuments(ctx context.Context, docs []schema.Document, options ...Option) ([]string, error)
SimilaritySearch(ctx context.Context, query string, numDocuments int, options ...Option) ([]schema.Document, error)
diff --git a/_content/blog/loopvar-preview.md b/_content/blog/loopvar-preview.md
index 0c88dcc..3c9150e 100644
--- a/_content/blog/loopvar-preview.md
+++ b/_content/blog/loopvar-preview.md
@@ -20,22 +20,24 @@
For example, consider this program:
{{raw `
- func main() {
- done := make(chan bool)
+~~~go
+func main() {
+ done := make(chan bool)
- values := []string{"a", "b", "c"}
- for _, v := range values {
- go func() {
- fmt.Println(v)
- done <- true
- }()
- }
-
- // wait for all goroutines to complete before exiting
- for _ = range values {
- <-done
- }
+ values := []string{"a", "b", "c"}
+ for _, v := range values {
+ go func() {
+ fmt.Println(v)
+ done <- true
+ }()
}
+
+ // wait for all goroutines to complete before exiting
+ for _ = range values {
+ <-done
+ }
+}
+~~~
`}}
The three created goroutines are all printing the same variable `v`,
@@ -49,15 +51,17 @@
This example has the same problem but no goroutines:
{{raw `
- func main() {
- var prints []func()
- for i := 1; i <= 3; i++ {
- prints = append(prints, func() { fmt.Println(i) })
- }
- for _, print := range prints {
- print()
- }
+~~~go
+func main() {
+ var prints []func()
+ for i := 1; i <= 3; i++ {
+ prints = append(prints, func() { fmt.Println(i) })
}
+ for _, print := range prints {
+ print()
+ }
+}
+~~~
`}}
This kind of mistake has caused production problems at many companies,
@@ -66,24 +70,26 @@
In that instance, the accidental capture of the loop variable was spread across
multiple functions and much more difficult to notice:
- // authz2ModelMapToPB converts a mapping of domain name to authz2Models into a
- // protobuf authorizations map
- func authz2ModelMapToPB(m map[string]authz2Model) (*sapb.Authorizations, error) {
- resp := &sapb.Authorizations{}
- for k, v := range m {
- // Make a copy of k because it will be reassigned with each loop.
- kCopy := k
- authzPB, err := modelToAuthzPB(&v)
- if err != nil {
- return nil, err
- }
- resp.Authz = append(resp.Authz, &sapb.Authorizations_MapElement{
- Domain: &kCopy,
- Authz: authzPB,
- })
+```go
+// authz2ModelMapToPB converts a mapping of domain name to authz2Models into a
+// protobuf authorizations map
+func authz2ModelMapToPB(m map[string]authz2Model) (*sapb.Authorizations, error) {
+ resp := &sapb.Authorizations{}
+ for k, v := range m {
+ // Make a copy of k because it will be reassigned with each loop.
+ kCopy := k
+ authzPB, err := modelToAuthzPB(&v)
+ if err != nil {
+ return nil, err
}
- return resp, nil
+ resp.Authz = append(resp.Authz, &sapb.Authorizations_MapElement{
+ Domain: &kCopy,
+ Authz: authzPB,
+ })
}
+ return resp, nil
+}
+```
The author of this code clearly understood the general problem, because they made a copy of `k`,
but it turns out `modelToAuthzPB` used pointers to fields in `v` when constructing its result,
@@ -106,17 +112,21 @@
This diff was in one program:
- for _, informer := range c.informerMap {
- + informer := informer
- go informer.Run(stopCh)
- }
+```go
+ for _, informer := range c.informerMap {
++ informer := informer
+ go informer.Run(stopCh)
+ }
+```
And this diff was in another program:
- for _, a := range alarms {
- + a := a
- go a.Monitor(b)
- }
+```go
+ for _, a := range alarms {
++ a := a
+ go a.Monitor(b)
+ }
+```
One of these two diffs is a bug fix; the other is an unnecessary change.
You can’t tell which is which unless you know more about the types
@@ -178,17 +188,19 @@
to prepare for that switch, we did have to correct many buggy tests that were not
testing what they thought they were, like this:
- func TestAllEvenBuggy(t *testing.T) {
- testCases := []int{1, 2, 4, 6}
- for _, v := range testCases {
- t.Run("sub", func(t *testing.T) {
- t.Parallel()
- if v&1 != 0 {
- t.Fatal("odd v", v)
- }
- })
- }
+```go
+func TestAllEvenBuggy(t *testing.T) {
+ testCases := []int{1, 2, 4, 6}
+ for _, v := range testCases {
+ t.Run("sub", func(t *testing.T) {
+ t.Parallel()
+ if v&1 != 0 {
+ t.Fatal("odd v", v)
+ }
+ })
}
+}
+```
In Go 1.21, this test passes because `t.Parallel` blocks each subtest
until the entire loop has finished and then runs all the subtests
diff --git a/_content/blog/maps.md b/_content/blog/maps.md
index aaebca3..a40d6cd 100644
--- a/_content/blog/maps.md
+++ b/_content/blog/maps.md
@@ -21,7 +21,9 @@
A Go map type looks like this:
- map[KeyType]ValueType
+```go
+map[KeyType]ValueType
+```
where `KeyType` may be any type that is [comparable](/ref/spec#Comparison_operators)
(more on this later),
@@ -29,7 +31,9 @@
This variable `m` is a map of string keys to int values:
- var m map[string]int
+```go
+var m map[string]int
+```
Map types are reference types, like pointers or slices,
and so the value of `m` above is `nil`;
@@ -38,7 +42,9 @@
but attempts to write to a nil map will cause a runtime panic; don't do that.
To initialize a map, use the built in `make` function:
- m = make(map[string]int)
+```go
+m = make(map[string]int)
+```
The `make` function allocates and initializes a hash map data structure
and returns a map value that points to it.
@@ -51,31 +57,43 @@
Go provides a familiar syntax for working with maps. This statement sets the key `"route"` to the value `66`:
- m["route"] = 66
+```go
+m["route"] = 66
+```
This statement retrieves the value stored under the key `"route"` and assigns it to a new variable i:
- i := m["route"]
+```go
+i := m["route"]
+```
If the requested key doesn't exist, we get the value type's _zero value_.
In this case the value type is `int`, so the zero value is `0`:
- j := m["root"]
- // j == 0
+```go
+j := m["root"]
+// j == 0
+```
The built in `len` function returns on the number of items in a map:
- n := len(m)
+```go
+n := len(m)
+```
The built in `delete` function removes an entry from the map:
- delete(m, "route")
+```go
+delete(m, "route")
+```
The `delete` function doesn't return anything, and will do nothing if the specified key doesn't exist.
A two-value assignment tests for the existence of a key:
- i, ok := m["route"]
+```go
+i, ok := m["route"]
+```
In this statement, the first value (`i`) is assigned the value stored under the key `"route"`.
If that key doesn't exist, `i` is the value type's zero value (`0`).
@@ -84,26 +102,34 @@
To test for a key without retrieving the value, use an underscore in place of the first value:
- _, ok := m["route"]
+```go
+_, ok := m["route"]
+```
To iterate over the contents of a map, use the `range` keyword:
- for key, value := range m {
- fmt.Println("Key:", key, "Value:", value)
- }
+```go
+for key, value := range m {
+ fmt.Println("Key:", key, "Value:", value)
+}
+```
To initialize a map with some data, use a map literal:
- commits := map[string]int{
- "rsc": 3711,
- "r": 2138,
- "gri": 1908,
- "adg": 912,
- }
+```go
+commits := map[string]int{
+ "rsc": 3711,
+ "r": 2138,
+ "gri": 1908,
+ "adg": 912,
+}
+```
The same syntax may be used to initialize an empty map, which is functionally identical to using the `make` function:
- m = map[string]int{}
+```go
+m = map[string]int{}
+```
## Exploiting zero values
@@ -160,44 +186,56 @@
Struct can be used to key data by multiple dimensions.
For example, this map of maps could be used to tally web page hits by country:
- hits := make(map[string]map[string]int)
+```go
+hits := make(map[string]map[string]int)
+```
This is map of string to (map of `string` to `int`).
Each key of the outer map is the path to a web page with its own inner map.
Each inner map key is a two-letter country code.
This expression retrieves the number of times an Australian has loaded the documentation page:
- n := hits["/doc/"]["au"]
+```go
+n := hits["/doc/"]["au"]
+```
Unfortunately, this approach becomes unwieldy when adding data,
as for any given outer key you must check if the inner map exists,
and create it if needed:
- func add(m map[string]map[string]int, path, country string) {
- mm, ok := m[path]
- if !ok {
- mm = make(map[string]int)
- m[path] = mm
- }
- mm[country]++
- }
- add(hits, "/doc/", "au")
+```go
+func add(m map[string]map[string]int, path, country string) {
+ mm, ok := m[path]
+ if !ok {
+ mm = make(map[string]int)
+ m[path] = mm
+ }
+ mm[country]++
+}
+add(hits, "/doc/", "au")
+```
On the other hand, a design that uses a single map with a struct key does away with all that complexity:
- type Key struct {
- Path, Country string
- }
- hits := make(map[Key]int)
+```go
+type Key struct {
+ Path, Country string
+}
+hits := make(map[Key]int)
+```
When a Vietnamese person visits the home page,
incrementing (and possibly creating) the appropriate counter is a one-liner:
- hits[Key{"/", "vn"}]++
+```go
+hits[Key{"/", "vn"}]++
+```
And it's similarly straightforward to see how many Swiss people have read the spec:
- n := hits[Key{"/ref/spec", "ch"}]
+```go
+n := hits[Key{"/ref/spec", "ch"}]
+```
## Concurrency
@@ -210,23 +248,29 @@
This statement declares a `counter` variable that is an anonymous struct
containing a map and an embedded `sync.RWMutex`.
- var counter = struct{
- sync.RWMutex
- m map[string]int
- }{m: make(map[string]int)}
+```go
+var counter = struct{
+ sync.RWMutex
+ m map[string]int
+}{m: make(map[string]int)}
+```
To read from the counter, take the read lock:
- counter.RLock()
- n := counter.m["some_key"]
- counter.RUnlock()
- fmt.Println("some_key:", n)
+```go
+counter.RLock()
+n := counter.m["some_key"]
+counter.RUnlock()
+fmt.Println("some_key:", n)
+```
To write to the counter, take the write lock:
- counter.Lock()
- counter.m["some_key"]++
- counter.Unlock()
+```go
+counter.Lock()
+counter.m["some_key"]++
+counter.Unlock()
+```
## Iteration order
@@ -236,14 +280,16 @@
If you require a stable iteration order you must maintain a separate data structure that specifies that order.
This example uses a separate sorted slice of keys to print a `map[int]string` in key order:
- import "sort"
+```go
+import "sort"
- var m map[int]string
- var keys []int
- for k := range m {
- keys = append(keys, k)
- }
- sort.Ints(keys)
- for _, k := range keys {
- fmt.Println("Key:", k, "Value:", m[k])
- }
+var m map[int]string
+var keys []int
+for k := range m {
+ keys = append(keys, k)
+}
+sort.Ints(keys)
+for _, k := range keys {
+ fmt.Println("Key:", k, "Value:", m[k])
+}
+```
diff --git a/_content/blog/matchlang.md b/_content/blog/matchlang.md
index 6ae43f5..558db20 100644
--- a/_content/blog/matchlang.md
+++ b/_content/blog/matchlang.md
@@ -207,19 +207,21 @@
Consider the following Matcher and lists of supported languages:
- var supported = []language.Tag{
- language.AmericanEnglish, // en-US: first language is fallback
- language.German, // de
- language.Dutch, // nl
- language.Portuguese // pt (defaults to Brazilian)
- language.EuropeanPortuguese, // pt-pT
- language.Romanian // ro
- language.Serbian, // sr (defaults to Cyrillic script)
- language.SerbianLatin, // sr-Latn
- language.SimplifiedChinese, // zh-Hans
- language.TraditionalChinese, // zh-Hant
- }
- var matcher = language.NewMatcher(supported)
+```go
+var supported = []language.Tag{
+ language.AmericanEnglish, // en-US: first language is fallback
+ language.German, // de
+ language.Dutch, // nl
+ language.Portuguese // pt (defaults to Brazilian)
+ language.EuropeanPortuguese, // pt-pT
+ language.Romanian // ro
+ language.Serbian, // sr (defaults to Cyrillic script)
+ language.SerbianLatin, // sr-Latn
+ language.SimplifiedChinese, // zh-Hans
+ language.TraditionalChinese, // zh-Hant
+}
+var matcher = language.NewMatcher(supported)
+```
Let's look at the matches against this list of supported languages for various
user preferences.
diff --git a/_content/blog/module-compatibility.md b/_content/blog/module-compatibility.md
index 50d5981..5f6a38d 100644
--- a/_content/blog/module-compatibility.md
+++ b/_content/blog/module-compatibility.md
@@ -35,19 +35,19 @@
When adding new arguments with sensible defaults, it’s tempting to add them as a variadic parameter. To extend the function
-```
+```go
func Run(name string)
```
with an additional `size` argument which defaults to zero, one might propose
-```
+```go
func Run(name string, size ...int)
```
on the grounds that all existing call sites will continue to work. While that is true, other uses of `Run` could break, like this one:
-```
+```go
package mypkg
var runner func(string) = yourpkg.Run
```
@@ -60,19 +60,19 @@
Instead, new functions were added. For example, the `database/sql` package's `Query` method’s signature was (and still is)
-```
+```go
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
```
When the `context` package was created, the Go team added a new method to `database/sql`:
-```
+```go
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
```
To avoid copying code, the old method calls the new one:
-```
+```go
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
return db.QueryContext(context.Background(), query, args...)
}
@@ -82,7 +82,7 @@
If you anticipate that a function may need more arguments in the future, you can plan ahead by making optional arguments a part of the function’s signature. The simplest way to do that is to add a single struct argument, as the [crypto/tls.Dial](https://pkg.go.dev/crypto/tls?tab=doc#Dial) function does:
-```
+```go
func Dial(network, addr string, config *Config) (*Conn, error)
```
@@ -90,13 +90,13 @@
Sometimes the techniques of adding a new function and adding options can be combined by making the options struct a method receiver. Consider the evolution of the `net` package’s ability to listen at a network address. Prior to Go 1.11, the `net` package provided only a `Listen` function with the signature
-```
+```go
func Listen(network, address string) (Listener, error)
```
For Go 1.11, two features were added to `net` listening: passing a context, and allowing the caller to provide a “control function” to adjust the raw connection after creation but before binding. The result could have been a new function that took a context, network, address and control function. Instead, the package authors added a [`ListenConfig`](https://pkg.go.dev/net@go1.11?tab=doc#ListenConfig) struct in anticipation that more options might be needed someday. And rather than define a new top-level function with a cumbersome name, they added a `Listen` method to `ListenConfig`:
-```
+```go
type ListenConfig struct {
Control func(network, address string, c syscall.RawConn) error
}
@@ -108,7 +108,7 @@
Option types fulfill the same role as struct options in function arguments: they are an extensible way to pass behavior-modifying configuration. Deciding which to choose is largely a matter of style. Consider this simple usage of gRPC's `DialOption` option type:
-```
+```go
grpc.Dial("some-target",
grpc.WithAuthority("some-authority"),
grpc.WithMaxDelay(time.Second),
@@ -117,7 +117,7 @@
This could also have been implemented as a struct option:
-```
+```go
notgrpc.Dial("some-target", ¬grpc.Options{
Authority: "some-authority",
MaxDelay: time.Second,
@@ -141,7 +141,7 @@
So, they decided to keep `tar.NewReader` signature unchanged, but type check for (and support) `io.Seeker` in `tar.Reader` methods:
-```
+```go
package tar
type Reader struct {
@@ -170,7 +170,7 @@
Tip: if you do need to use an interface but don't intend for users to implement it, you can add an unexported method. This prevents types defined outside your package from satisfying your interface without embedding, freeing you to add methods later without breaking user implementations. For example, see [`testing.TB`'s `private()` function](https://github.com/golang/go/blob/83b181c68bf332ac7948f145f33d128377a09c42/src/testing/testing.go#L564-L567).
-```
+```go
// TB is the interface common to T and B.
type TB interface {
Error(args ...interface{})
@@ -204,7 +204,7 @@
To prevent comparison in the first place, make sure the struct has a non-comparable field. It may have one already—no slice, map or function type is comparable—but if not, one can be added like so:
-```
+```go
type Point struct {
_ [0]func()
X int
@@ -214,7 +214,7 @@
The `func()` type is not comparable, and the zero-length array takes up no space. We can define a type to clarify our intent:
-```
+```go
type doNotCompare [0]func()
type Point struct {
diff --git a/_content/blog/normalization.md b/_content/blog/normalization.md
index 948e7cb..fe02228 100644
--- a/_content/blog/normalization.md
+++ b/_content/blog/normalization.md
@@ -140,14 +140,18 @@
[unicode/norm](https://pkg.go.dev/golang.org/x/text/unicode/norm) package
to wrap your `io.Writer` of choice:
- wc := norm.NFC.Writer(w)
- defer wc.Close()
- // write as before...
+```go
+wc := norm.NFC.Writer(w)
+defer wc.Close()
+// write as before...
+```
If you have a small string and want to do a quick conversion, you can use this
simpler form:
- norm.NFC.Bytes(b)
+```go
+norm.NFC.Bytes(b)
+```
Package norm provides various other methods for normalizing text.
Pick the one that suits your needs best.
@@ -173,18 +177,22 @@
Consider a case where you want to search and replace the word "cafe" with its
plural form "cafes". A code snippet could look like this.
- s := "We went to eat at multiple cafe"
- cafe := "cafe"
- if p := strings.Index(s, cafe); p != -1 {
- p += len(cafe)
- s = s[:p] + "s" + s[p:]
- }
- fmt.Println(s)
+```go
+s := "We went to eat at multiple cafe"
+cafe := "cafe"
+if p := strings.Index(s, cafe); p != -1 {
+ p += len(cafe)
+ s = s[:p] + "s" + s[p:]
+}
+fmt.Println(s)
+```
This prints "We went to eat at multiple cafes" as desired and expected. Now
consider our text contains the French spelling "café" in NFD form:
- s := "We went to eat at multiple cafe\u0301"
+```go
+s := "We went to eat at multiple cafe\u0301"
+```
Using the same code from above, the plural "s" would still be inserted after
the 'e', but before the acute, resulting in "We went to eat at multiple
@@ -194,16 +202,18 @@
characters and inserts a rune in the middle of a character. Using the norm
package, we can rewrite this piece of code as follows:
- s := "We went to eat at multiple cafe\u0301"
- cafe := "cafe"
- if p := strings.Index(s, cafe); p != -1 {
- p += len(cafe)
- if bp := norm.FirstBoundary(s[p:]); bp > 0 {
- p += bp
- }
- s = s[:p] + "s" + s[p:]
+```go
+s := "We went to eat at multiple cafe\u0301"
+cafe := "cafe"
+if p := strings.Index(s, cafe); p != -1 {
+ p += len(cafe)
+ if bp := norm.FirstBoundary(s[p:]); bp > 0 {
+ p += bp
}
- fmt.Println(s)
+ s = s[:p] + "s" + s[p:]
+}
+fmt.Println(s)
+```
This may be a contrived example, but the gist should be clear. Be mindful of
the fact that characters can span multiple runes. Generally these kinds of
@@ -227,23 +237,27 @@
decomposes text into its smallest parts, removes all accents, and then
recomposes the text into NFC:
- import (
- "unicode"
+```go
+import (
+ "unicode"
- "golang.org/x/text/transform"
- "golang.org/x/text/unicode/norm"
- )
+ "golang.org/x/text/transform"
+ "golang.org/x/text/unicode/norm"
+)
- isMn := func(r rune) bool {
- return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
- }
- t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
+isMn := func(r rune) bool {
+ return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
+}
+t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
+```
The resulting `Transformer` can be used to remove accents from an `io.Reader`
of choice as follows:
- r = transform.NewReader(r, t)
- // read as before ...
+```go
+r = transform.NewReader(r, t)
+// read as before ...
+```
This will, for example, convert any mention of "cafés" in the text to "cafes",
regardless of the normal form in which the original text was encoded.
diff --git a/_content/blog/osroot.md b/_content/blog/osroot.md
index e6e319b..a341d0d 100644
--- a/_content/blog/osroot.md
+++ b/_content/blog/osroot.md
@@ -25,36 +25,44 @@
If the attacker controls part of the filename, they may be able to use relative
directory components ("..") to escape the intended location:
- f, err := os.Open(filepath.Join(trustedLocation, "../../../../etc/passwd"))
+```go
+f, err := os.Open(filepath.Join(trustedLocation, "../../../../etc/passwd"))
+```
On Windows systems, some names have special meaning:
- // f will print to the console.
- f, err := os.Create(filepath.Join(trustedLocation, "CONOUT$"))
+```go
+// f will print to the console.
+f, err := os.Create(filepath.Join(trustedLocation, "CONOUT$"))
+```
If the attacker controls part of the local filesystem, they may be able to use
symbolic links to cause a program to access the wrong file:
- // Attacker links /home/user/.config to /home/otheruser/.config:
- err := os.WriteFile("/home/user/.config/foo", config, 0o666)
+```go
+// Attacker links /home/user/.config to /home/otheruser/.config:
+err := os.WriteFile("/home/user/.config/foo", config, 0o666)
+```
If the program defends against symlink traversal by first verifying that the intended file
does not contain any symlinks, it may still be vulnerable to
[time-of-check/time-of-use (TOCTOU) races](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use),
where the attacker creates a symlink after the program's check:
- // Validate the path before use.
- cleaned, err := filepath.EvalSymlinks(unsafePath)
- if err != nil {
- return err
- }
- if !filepath.IsLocal(cleaned) {
- return errors.New("unsafe path")
- }
+```go
+// Validate the path before use.
+cleaned, err := filepath.EvalSymlinks(unsafePath)
+if err != nil {
+ return err
+}
+if !filepath.IsLocal(cleaned) {
+ return errors.New("unsafe path")
+}
- // Attacker replaces part of the path with a symlink.
- // The Open call follows the symlink:
- f, err := os.Open(cleaned)
+// Attacker replaces part of the path with a symlink.
+// The Open call follows the symlink:
+f, err := os.Open(cleaned)
+```
Another variety of TOCTOU race involves moving a directory that forms part of a path
mid-traversal. For example, the attacker provides a path such as "a/b/c/../../etc/passwd",
@@ -115,18 +123,22 @@
in the local filesystem. Open a root with the [`os.OpenRoot`](/pkg/os#OpenRoot)
function:
- root, err := os.OpenRoot("/some/root/directory")
- if err != nil {
- return err
- }
- defer root.Close()
+```go
+root, err := os.OpenRoot("/some/root/directory")
+if err != nil {
+ return err
+}
+defer root.Close()
+```
`Root` provides methods to operate on files within the root.
These methods all accept filenames relative to the root,
and disallow any operations that would escape from the root either
using relative path components ("..") or symlinks.
- f, err := root.Open("path/to/file")
+```go
+f, err := root.Open("path/to/file")
+```
`Root` permits relative path components and symlinks that do not escape the root.
For example, `root.Open("a/../b")` is permitted. Filenames are resolved using the
@@ -136,21 +148,25 @@
`Root` currently provides the following set of operations:
- func (*Root) Create(string) (*File, error)
- func (*Root) Lstat(string) (fs.FileInfo, error)
- func (*Root) Mkdir(string, fs.FileMode) error
- func (*Root) Open(string) (*File, error)
- func (*Root) OpenFile(string, int, fs.FileMode) (*File, error)
- func (*Root) OpenRoot(string) (*Root, error)
- func (*Root) Remove(string) error
- func (*Root) Stat(string) (fs.FileInfo, error)
+```go
+func (*Root) Create(string) (*File, error)
+func (*Root) Lstat(string) (fs.FileInfo, error)
+func (*Root) Mkdir(string, fs.FileMode) error
+func (*Root) Open(string) (*File, error)
+func (*Root) OpenFile(string, int, fs.FileMode) (*File, error)
+func (*Root) OpenRoot(string) (*Root, error)
+func (*Root) Remove(string) error
+func (*Root) Stat(string) (fs.FileInfo, error)
+```
In addition to the `Root` type, the new
[`os.OpenInRoot`](/pkg/os#OpenInRoot) function
provides a simple way to open a potentially-untrusted filename within a
specific directory:
- f, err := os.OpenInRoot("/some/root/directory", untrustedFilename)
+```go
+f, err := os.OpenInRoot("/some/root/directory", untrustedFilename)
+```
The `Root` type provides a simple, safe, portable API for operating with untrusted filenames.
@@ -226,11 +242,13 @@
As a good rule of thumb, code which calls `filepath.Join` to combine a fixed directory
and an externally-provided filename should probably use `os.Root` instead.
- // This might open a file not located in baseDirectory.
- f, err := os.Open(filepath.Join(baseDirectory, filename))
+```go
+// This might open a file not located in baseDirectory.
+f, err := os.Open(filepath.Join(baseDirectory, filename))
- // This will only open files under baseDirectory.
- f, err := os.OpenInRoot(baseDirectory, filename)
+// This will only open files under baseDirectory.
+f, err := os.OpenInRoot(baseDirectory, filename)
+```
## Future work
diff --git a/_content/blog/package-names.md b/_content/blog/package-names.md
index 1aebd11..5bd5188 100644
--- a/_content/blog/package-names.md
+++ b/_content/blog/package-names.md
@@ -90,24 +90,30 @@
When a function in package pkg returns a value of type `pkg.Pkg` (or
`*pkg.Pkg`), the function name can often omit the type name without confusion:
- start := time.Now() // start is a time.Time
- t, err := time.Parse(time.Kitchen, "6:06PM") // t is a time.Time
- ctx = context.WithTimeout(ctx, 10*time.Millisecond) // ctx is a context.Context
- ip, ok := userip.FromContext(ctx) // ip is a net.IP
+```go
+start := time.Now() // start is a time.Time
+t, err := time.Parse(time.Kitchen, "6:06PM") // t is a time.Time
+ctx = context.WithTimeout(ctx, 10*time.Millisecond) // ctx is a context.Context
+ip, ok := userip.FromContext(ctx) // ip is a net.IP
+```
A function named `New` in package `pkg` returns a value of type `pkg.Pkg`.
This is a standard entry point for client code using that type:
- q := list.New() // q is a *list.List
+```go
+ q := list.New() // q is a *list.List
+```
When a function returns a value of type `pkg.T`, where `T` is not `Pkg`, the
function name may include `T` to make client code easier to understand.
A common situation is a package with multiple New-like functions:
- d, err := time.ParseDuration("10s") // d is a time.Duration
- elapsed := time.Since(start) // elapsed is a time.Duration
- ticker := time.NewTicker(d) // ticker is a *time.Ticker
- timer := time.NewTimer(d) // timer is a *time.Timer
+```go
+d, err := time.ParseDuration("10s") // d is a time.Duration
+elapsed := time.Since(start) // elapsed is a time.Duration
+ticker := time.NewTicker(d) // ticker is a *time.Ticker
+timer := time.NewTimer(d) // timer is a *time.Timer
+```
Types in different packages can have the same name, because from the client's
point of view such names are discriminated by the package name.
@@ -130,12 +136,14 @@
Client code uses the package path when importing the package.
By convention, the last element of the package path is the package name:
- import (
- "context" // package context
- "fmt" // package fmt
- "golang.org/x/time/rate" // package rate
- "os/exec" // package exec
- )
+```go
+import (
+ "context" // package context
+ "fmt" // package fmt
+ "golang.org/x/time/rate" // package rate
+ "os/exec" // package exec
+)
+```
Build tools map package paths onto directories.
The go tool uses the [GOPATH](/doc/code.html#GOPATH)
@@ -187,38 +195,50 @@
pull them into their own package.
For example, if you have
- package util
- func NewStringSet(...string) map[string]bool {...}
- func SortStringSet(map[string]bool) []string {...}
+```go
+package util
+func NewStringSet(...string) map[string]bool {...}
+func SortStringSet(map[string]bool) []string {...}
+```
then client code looks like
- set := util.NewStringSet("c", "a", "b")
- fmt.Println(util.SortStringSet(set))
+```go
+set := util.NewStringSet("c", "a", "b")
+fmt.Println(util.SortStringSet(set))
+```
Pull these functions out of `util` into a new package, choosing a name that fits
the contents:
- package stringset
- func New(...string) map[string]bool {...}
- func Sort(map[string]bool) []string {...}
+```go
+package stringset
+func New(...string) map[string]bool {...}
+func Sort(map[string]bool) []string {...}
+```
then the client code becomes
- set := stringset.New("c", "a", "b")
- fmt.Println(stringset.Sort(set))
+```go
+set := stringset.New("c", "a", "b")
+fmt.Println(stringset.Sort(set))
+```
Once you've made this change, it's easier to see how to improve the new package:
- package stringset
- type Set map[string]bool
- func New(...string) Set {...}
- func (s Set) Sort() []string {...}
+```go
+package stringset
+type Set map[string]bool
+func New(...string) Set {...}
+func (s Set) Sort() []string {...}
+```
which yields even simpler client code:
- set := stringset.New("c", "a", "b")
- fmt.Println(set.Sort())
+```go
+set := stringset.New("c", "a", "b")
+fmt.Println(set.Sort())
+```
The name of the package is a critical piece of its design.
Work to eliminate meaningless package names from your projects.
diff --git a/_content/blog/path-security.md b/_content/blog/path-security.md
index 7f647ff..0a99042 100644
--- a/_content/blog/path-security.md
+++ b/_content/blog/path-security.md
@@ -93,7 +93,9 @@
implements the Unix rules on Unix and the Windows rules on Windows.
For example, this command
- out, err := exec.Command("go", "version").CombinedOutput()
+```go
+out, err := exec.Command("go", "version").CombinedOutput()
+```
behaves the same as typing `go` `version` into the operating system shell.
On Windows, it runs `.\go.exe` when that exists.
@@ -121,9 +123,11 @@
in the package source directory, it does the PATH lookup
from the original directory where the `go` command was invoked:
- cmd := exec.Command("gcc", "file.c")
- cmd.Dir = "badpkg"
- cmd.Run()
+```go
+cmd := exec.Command("gcc", "file.c")
+cmd.Dir = "badpkg"
+cmd.Run()
+```
So even if `badpkg\gcc.exe` exists on a Windows system,
this code snippet will not find it.
@@ -134,9 +138,11 @@
and in that case there's not even a path lookup,
because `cgo` always comes from GOROOT:
- cmd := exec.Command(GOROOT+"/pkg/tool/"+GOOS_GOARCH+"/cgo", "file.go")
- cmd.Dir = "badpkg"
- cmd.Run()
+```go
+cmd := exec.Command(GOROOT+"/pkg/tool/"+GOOS_GOARCH+"/cgo", "file.go")
+cmd.Dir = "badpkg"
+cmd.Run()
+```
This is even safer than the previous snippet:
there's no chance of running any bad `cgo.exe` that may exist.
@@ -144,9 +150,11 @@
But it turns out that cgo itself also invokes the host C compiler,
on some temporary files it creates, meaning it executes this code itself:
- // running in cgo in badpkg dir
- cmd := exec.Command("gcc", "tmpfile.c")
- cmd.Run()
+```go
+// running in cgo in badpkg dir
+cmd := exec.Command("gcc", "tmpfile.c")
+cmd.Run()
+```
Now, because cgo itself is running in `badpkg`,
not in the directory where the `go` command was run,
@@ -259,11 +267,15 @@
of `os/exec` as [`golang.org/x/sys/execabs`](https://pkg.go.dev/golang.org/x/sys/execabs).
You can use it in your program by simply replacing
- import "os/exec"
+```go
+import "os/exec"
+```
with
- import exec "golang.org/x/sys/execabs"
+```go
+import exec "golang.org/x/sys/execabs"
+```
and recompiling.
diff --git a/_content/blog/pgo-preview.md b/_content/blog/pgo-preview.md
index 6f35e52..a11d06a 100644
--- a/_content/blog/pgo-preview.md
+++ b/_content/blog/pgo-preview.md
@@ -42,7 +42,7 @@
In `main.go`:
-```
+```go
package main
import (
diff --git a/_content/blog/pgo.md b/_content/blog/pgo.md
index 28fdfa4..68fa207 100644
--- a/_content/blog/pgo.md
+++ b/_content/blog/pgo.md
@@ -47,7 +47,7 @@
In `main.go`:
-```
+```go
package main
import (
@@ -516,7 +516,7 @@
Before getting to PGO-driven devirtualization, let’s step back and define "devirtualization" in general.
Suppose you have code that looks like something like this:
-```
+```go
f, _ := os.Open("foo.txt")
var r io.Reader = f
r.Read(b)
@@ -538,7 +538,7 @@
PGO-driven devirtualization extends this concept to situations where the concrete type is not statically known, but profiling can show that, for example, an `io.Reader.Read` call targets `os.(*File).Read` most of the time.
In this case, PGO can replace `r.Read(b)` with something like:
-```
+```go
if f, ok := r.(*os.File); ok {
f.Read(b)
} else {
diff --git a/_content/blog/pipelines.md b/_content/blog/pipelines.md
index 91be4b6..69330d0 100644
--- a/_content/blog/pipelines.md
+++ b/_content/blog/pipelines.md
@@ -130,10 +130,12 @@
buffer:
{{raw `
- c := make(chan int, 2) // buffer size 2
- c <- 1 // succeeds immediately
- c <- 2 // succeeds immediately
- c <- 3 // blocks until another goroutine does <-c and receives 1
+~~~go
+c := make(chan int, 2) // buffer size 2
+c <- 1 // succeeds immediately
+c <- 2 // succeeds immediately
+c <- 3 // blocks until another goroutine does <-c and receives 1
+~~~
`}}
When the number of values to be sent is known at channel creation time, a buffer
diff --git a/_content/blog/playground.md b/_content/blog/playground.md
index d48d475..a26dffa 100644
--- a/_content/blog/playground.md
+++ b/_content/blog/playground.md
@@ -228,15 +228,17 @@
actual system call.
For instance, here is the [`syscall.Open`](https://github.com/golang/go/blob/2197321db1dd997165c0091ba2bcb3b6be7633d0/src/syscall/fs_nacl.go#L473) function:
- func Open(path string, openmode int, perm uint32) (fd int, err error) {
- fs.mu.Lock()
- defer fs.mu.Unlock()
- f, err := fs.open(path, openmode, perm&0777|S_IFREG)
- if err != nil {
- return -1, err
- }
- return newFD(f), nil
+```go
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+ fs.mu.Lock()
+ defer fs.mu.Unlock()
+ f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+ if err != nil {
+ return -1, err
}
+ return newFD(f), nil
+}
+```
File descriptors are tracked by a global slice named
[`files`](https://github.com/golang/go/blob/2197321db1dd997165c0091ba2bcb3b6be7633d0/src/syscall/fd_nacl.go#L17).
diff --git a/_content/blog/pprof.md b/_content/blog/pprof.md
index 246a7b9..77c041f 100644
--- a/_content/blog/pprof.md
+++ b/_content/blog/pprof.md
@@ -97,19 +97,21 @@
In a standalone program like this one, we have to import `runtime/pprof` and add a few
lines of code:
- var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
+```go
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
- func main() {
- flag.Parse()
- if *cpuprofile != "" {
- f, err := os.Create(*cpuprofile)
- if err != nil {
- log.Fatal(err)
- }
- pprof.StartCPUProfile(f)
- defer pprof.StopCPUProfile()
- }
- ...
+func main() {
+ flag.Parse()
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+ ...
+```
The new code defines a flag named `cpuprofile`, calls the
[Go flag library](/pkg/flag/) to parse the command line flags,
@@ -303,19 +305,21 @@
We'll arrange that if the `-memprofile` flag is supplied, the program stops after one
iteration of the loop finding, writes a memory profile, and exits:
- var memprofile = flag.String("memprofile", "", "write memory profile to this file")
- ...
+```go
+var memprofile = flag.String("memprofile", "", "write memory profile to this file")
+...
- FindHavlakLoops(cfgraph, lsgraph)
- if *memprofile != "" {
- f, err := os.Create(*memprofile)
- if err != nil {
- log.Fatal(err)
- }
- pprof.WriteHeapProfile(f)
- f.Close()
- return
+ FindHavlakLoops(cfgraph, lsgraph)
+ if *memprofile != "" {
+ f, err := os.Create(*memprofile)
+ if err != nil {
+ log.Fatal(err)
}
+ pprof.WriteHeapProfile(f)
+ f.Close()
+ return
+ }
+```
We invoke the program with `-memprofile` flag to write a profile:
@@ -418,14 +422,16 @@
to insert a duplicate element.
In the one remaining case, we can write a simple variant of the `append` built-in function:
- func appendUnique(a []int, x int) []int {
- for _, y := range a {
- if x == y {
- return a
- }
- }
- return append(a, x)
- }
+```go
+func appendUnique(a []int, x int) []int {
+ for _, y := range a {
+ if x == y {
+ return a
+ }
+ }
+ return append(a, x)
+}
+```
In addition to writing that function, changing the Go program to use slices instead
of maps requires changing just a few lines of code.
@@ -525,47 +531,51 @@
We'll add a global `cache` structure:
- var cache struct {
- size int
- nonBackPreds [][]int
- backPreds [][]int
- number []int
- header []int
- types []int
- last []int
- nodes []*UnionFindNode
- }
+```go
+var cache struct {
+ size int
+ nonBackPreds [][]int
+ backPreds [][]int
+ number []int
+ header []int
+ types []int
+ last []int
+ nodes []*UnionFindNode
+}
+```
and then have `FindLoops` consult it as a replacement for allocation:
{{raw `
- if cache.size < size {
- cache.size = size
- cache.nonBackPreds = make([][]int, size)
- cache.backPreds = make([][]int, size)
- cache.number = make([]int, size)
- cache.header = make([]int, size)
- cache.types = make([]int, size)
- cache.last = make([]int, size)
- cache.nodes = make([]*UnionFindNode, size)
- for i := range cache.nodes {
- cache.nodes[i] = new(UnionFindNode)
- }
- }
+~~~go
+if cache.size < size {
+ cache.size = size
+ cache.nonBackPreds = make([][]int, size)
+ cache.backPreds = make([][]int, size)
+ cache.number = make([]int, size)
+ cache.header = make([]int, size)
+ cache.types = make([]int, size)
+ cache.last = make([]int, size)
+ cache.nodes = make([]*UnionFindNode, size)
+ for i := range cache.nodes {
+ cache.nodes[i] = new(UnionFindNode)
+ }
+}
- nonBackPreds := cache.nonBackPreds[:size]
- for i := range nonBackPreds {
- nonBackPreds[i] = nonBackPreds[i][:0]
- }
- backPreds := cache.backPreds[:size]
- for i := range nonBackPreds {
- backPreds[i] = backPreds[i][:0]
- }
- number := cache.number[:size]
- header := cache.header[:size]
- types := cache.types[:size]
- last := cache.last[:size]
- nodes := cache.nodes[:size]
+nonBackPreds := cache.nonBackPreds[:size]
+for i := range nonBackPreds {
+ nonBackPreds[i] = nonBackPreds[i][:0]
+}
+backPreds := cache.backPreds[:size]
+for i := range nonBackPreds {
+ backPreds[i] = backPreds[i][:0]
+}
+number := cache.number[:size]
+header := cache.header[:size]
+types := cache.types[:size]
+last := cache.last[:size]
+nodes := cache.nodes[:size]
+~~~
`}}
Such a global variable is bad engineering practice, of course: it means that
@@ -656,7 +666,9 @@
[benchmark function](/pkg/testing/) and you're all set.
There is also a standard HTTP interface to profiling data. In an HTTP server, adding
- import _ "net/http/pprof"
+```go
+import _ "net/http/pprof"
+```
will install handlers for a few URLs under `/debug/pprof/`.
Then you can run `go tool pprof` with a single argument—the URL to your server's
diff --git a/_content/blog/protobuf-apiv2.md b/_content/blog/protobuf-apiv2.md
index e6b972c..aa02cec 100644
--- a/_content/blog/protobuf-apiv2.md
+++ b/_content/blog/protobuf-apiv2.md
@@ -92,19 +92,23 @@
Next, we will write a Go function which accepts an arbitrary message
value and removes all the sensitive fields.
- // Redact clears every sensitive field in pb.
- func Redact(pb proto.Message) {
- // ...
- }
+```go
+// Redact clears every sensitive field in pb.
+func Redact(pb proto.Message) {
+ // ...
+}
+```
This function accepts a
[`proto.Message`](https://pkg.go.dev/google.golang.org/protobuf/proto?tab=doc#Message),
an interface type implemented by all generated message types. This type
is an alias for one defined in the `protoreflect` package:
- type ProtoMessage interface{
- ProtoReflect() Message
- }
+```go
+type ProtoMessage interface{
+ ProtoReflect() Message
+}
+```
To avoid filling up the namespace of generated
messages, the interface contains only a single method returning a
@@ -119,11 +123,13 @@
[`protoreflect.Message.Range`](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#Message.Range)
method calls a function for every populated field in a message.
- m := pb.ProtoReflect()
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- // ...
- return true
- })
+```go
+m := pb.ProtoReflect()
+m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ // ...
+ return true
+})
+```
The range function is called with a
[`protoreflect.FieldDescriptor`](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect?tab=doc#FieldDescriptor)
@@ -136,7 +142,9 @@
method returns the field options as a `google.protobuf.FieldOptions`
message.
- opts := fd.Options().(*descriptorpb.FieldOptions)
+```go
+opts := fd.Options().(*descriptorpb.FieldOptions)
+```
(Why the type assertion? Since the generated `descriptorpb` package
depends on `protoreflect`, the `protoreflect` package can't return the
@@ -144,9 +152,11 @@
We can then check the options to see the value of our extension boolean:
- if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
- return true // don't redact non-sensitive fields
- }
+```go
+if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
+ return true // don't redact non-sensitive fields
+}
+```
Note that we are looking at the field _descriptor_ here, not the field
_value_. The information we're interested in lies in the protocol
@@ -162,22 +172,26 @@
Once we have identified a field that needs redaction, clearing it is simple:
- m.Clear(fd)
+```go
+m.Clear(fd)
+```
Putting all the above together, our complete redaction function is:
- // Redact clears every sensitive field in pb.
- func Redact(pb proto.Message) {
- m := pb.ProtoReflect()
- m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- opts := fd.Options().(*descriptorpb.FieldOptions)
- if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
- return true
- }
- m.Clear(fd)
+```go
+// Redact clears every sensitive field in pb.
+func Redact(pb proto.Message) {
+ m := pb.ProtoReflect()
+ m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
+ opts := fd.Options().(*descriptorpb.FieldOptions)
+ if proto.GetExtension(opts, policypb.E_NonSensitive).(bool) {
return true
- })
- }
+ }
+ m.Clear(fd)
+ return true
+ })
+}
+```
A more complete implementation might recursively descend into
message-valued fields. We hope that this simple example gives a
diff --git a/_content/blog/protobuf-opaque.md b/_content/blog/protobuf-opaque.md
index 65ac714..9ed1735 100644
--- a/_content/blog/protobuf-opaque.md
+++ b/_content/blog/protobuf-opaque.md
@@ -56,18 +56,20 @@
(`protoc`)](https://protobuf.dev/getting-started/gotutorial/) to generate code
like the following (in a `.pb.go` file):
- package logpb
+```go
+package logpb
- type LogEntry struct {
- BackendServer *string
- RequestSize *uint32
- IPAddress *string
- // …internal fields elided…
- }
+type LogEntry struct {
+ BackendServer *string
+ RequestSize *uint32
+ IPAddress *string
+ // …internal fields elided…
+}
- func (l *LogEntry) GetBackendServer() string { … }
- func (l *LogEntry) GetRequestSize() uint32 { … }
- func (l *LogEntry) GetIPAddress() string { … }
+func (l *LogEntry) GetBackendServer() string { … }
+func (l *LogEntry) GetRequestSize() uint32 { … }
+func (l *LogEntry) GetIPAddress() string { … }
+```
Now you can import the generated `logpb` package from your Go code and call
functions like
@@ -110,9 +112,11 @@
one could use the `flag` package to parse command-line flag values into protobuf
message fields:
- var req logpb.LogEntry
- flag.StringVar(&req.BackendServer, "backend", os.Getenv("HOST"), "…")
- flag.Parse() // fills the BackendServer field from -backend flag
+```go
+var req logpb.LogEntry
+flag.StringVar(&req.BackendServer, "backend", os.Getenv("HOST"), "…")
+flag.Parse() // fills the BackendServer field from -backend flag
+```
The problem with such a tight coupling is that we can never change how we lay
out protobuf messages in memory. Lifting this restriction enables many
@@ -121,20 +125,22 @@
What changes with the new Opaque API? Here is how the generated code from the
above example would change:
- package logpb
+```go
+package logpb
- type LogEntry struct {
- xxx_hidden_BackendServer *string // no longer exported
- xxx_hidden_RequestSize uint32 // no longer exported
- xxx_hidden_IPAddress *string // no longer exported
- // …internal fields elided…
- }
+type LogEntry struct {
+ xxx_hidden_BackendServer *string // no longer exported
+ xxx_hidden_RequestSize uint32 // no longer exported
+ xxx_hidden_IPAddress *string // no longer exported
+ // …internal fields elided…
+}
- func (l *LogEntry) GetBackendServer() string { … }
- func (l *LogEntry) HasBackendServer() bool { … }
- func (l *LogEntry) SetBackendServer(string) { … }
- func (l *LogEntry) ClearBackendServer() { … }
- // …
+func (l *LogEntry) GetBackendServer() string { … }
+func (l *LogEntry) HasBackendServer() bool { … }
+func (l *LogEntry) SetBackendServer(string) { … }
+func (l *LogEntry) ClearBackendServer() { … }
+// …
+```
With the Opaque API, the struct fields are hidden and can no longer be
directly accessed. Instead, the new accessor methods allow for getting, setting,
@@ -243,13 +249,17 @@
A simple mistake is to compare the `device_type` enum field like so:
- if cv.DeviceType == logpb.LogEntry_DESKTOP.Enum() { // incorrect!
+```go
+if cv.DeviceType == logpb.LogEntry_DESKTOP.Enum() { // incorrect!
+```
Did you spot the bug? The condition compares the memory address instead of the
value. Because the `Enum()` accessor allocates a new variable on each call, the
condition can never be true. The check should have read:
- if cv.GetDeviceType() == logpb.LogEntry_DESKTOP {
+```go
+if cv.GetDeviceType() == logpb.LogEntry_DESKTOP {
+```
The new Opaque API prevents this mistake: Because fields are hidden, all access
must go through the getter.
@@ -261,26 +271,32 @@
part of the request middleware looks correct, but still the entire service goes
down whenever just one customer sends a high volume of requests:
- logEntry.IPAddress = req.IPAddress
- logEntry.BackendServer = proto.String(hostname)
- // The redactIP() function redacts IPAddress to 127.0.0.1,
- // unexpectedly not just in logEntry *but also* in req!
- go auditlog(redactIP(logEntry))
- if quotaExceeded(req) {
- // BUG: All requests end up here, regardless of their source.
- return fmt.Errorf("server overloaded")
- }
+```go
+logEntry.IPAddress = req.IPAddress
+logEntry.BackendServer = proto.String(hostname)
+// The redactIP() function redacts IPAddress to 127.0.0.1,
+// unexpectedly not just in logEntry *but also* in req!
+go auditlog(redactIP(logEntry))
+if quotaExceeded(req) {
+ // BUG: All requests end up here, regardless of their source.
+ return fmt.Errorf("server overloaded")
+}
+```
Did you spot the bug? The first line accidentally copied the pointer (thereby
sharing the pointed-to variable between the `logEntry` and `req` messages)
instead of its value. It should have read:
- logEntry.IPAddress = proto.String(req.GetIPAddress())
+```go
+logEntry.IPAddress = proto.String(req.GetIPAddress())
+```
The new Opaque API prevents this problem as the setter takes a value
(`string`) instead of a pointer:
- logEntry.SetIPAddress(req.GetIPAddress())
+```go
+logEntry.SetIPAddress(req.GetIPAddress())
+```
### Motivation: Fix Sharp Edges: reflection {#reflection}
diff --git a/_content/blog/race-detector.md b/_content/blog/race-detector.md
index ee11a7c..df9f33e 100644
--- a/_content/blog/race-detector.md
+++ b/_content/blog/race-detector.md
@@ -70,21 +70,23 @@
To try out the race detector for yourself, copy this example program into `racy.go`:
{{raw `
- package main
+~~~go
+package main
- import "fmt"
+import "fmt"
- func main() {
- done := make(chan bool)
- m := make(map[string]string)
- m["name"] = "world"
- go func() {
- m["name"] = "data race"
- done <- true
- }()
- fmt.Println("Hello,", m["name"])
- <-done
- }
+func main() {
+ done := make(chan bool)
+ m := make(map[string]string)
+ m["name"] = "world"
+ go func() {
+ m["name"] = "data race"
+ done <- true
+ }()
+ fmt.Println("Hello,", m["name"])
+ <-done
+}
+~~~
`}}
Then run it with the race detector enabled:
@@ -171,7 +173,9 @@
It is commonly used with [`io.Copy`](/pkg/io/#Copy)
to drain a reader, like this:
- io.Copy(ioutil.Discard, reader)
+```go
+io.Copy(ioutil.Discard, reader)
+```
Back in July 2011 the Go team noticed that using `Discard` in this way was
inefficient: the `Copy` function allocates an internal 32 kB buffer each time it
@@ -182,11 +186,15 @@
The fix was simple.
If the given `Writer` implements a `ReadFrom` method, a `Copy` call like this:
- io.Copy(writer, reader)
+```go
+io.Copy(writer, reader)
+```
is delegated to this potentially more efficient call:
- writer.ReadFrom(reader)
+```go
+writer.ReadFrom(reader)
+```
We
[added a ReadFrom method](/cl/4817041)
@@ -216,27 +224,33 @@
Brad's program includes a `trackDigestReader` type, which wraps an `io.Reader`
and records the hash digest of what it reads.
- type trackDigestReader struct {
- r io.Reader
- h hash.Hash
- }
+```go
+type trackDigestReader struct {
+ r io.Reader
+ h hash.Hash
+}
- func (t trackDigestReader) Read(p []byte) (n int, err error) {
- n, err = t.r.Read(p)
- t.h.Write(p[:n])
- return
- }
+func (t trackDigestReader) Read(p []byte) (n int, err error) {
+ n, err = t.r.Read(p)
+ t.h.Write(p[:n])
+ return
+}
+```
For example, it could be used to compute the SHA-1 hash of a file while reading it:
- tdr := trackDigestReader{r: file, h: sha1.New()}
- io.Copy(writer, tdr)
- fmt.Printf("File hash: %x", tdr.h.Sum(nil))
+```go
+tdr := trackDigestReader{r: file, h: sha1.New()}
+io.Copy(writer, tdr)
+fmt.Printf("File hash: %x", tdr.h.Sum(nil))
+```
In some cases there would be nowhere to write the data—but still a need to hash
the file—and so `Discard` would be used:
- io.Copy(ioutil.Discard, tdr)
+```go
+io.Copy(ioutil.Discard, tdr)
+```
But in this case the `blackHole` buffer isn't just a black hole; it is a
legitimate place to store the data between reading it from the source
@@ -246,14 +260,16 @@
between reading and hashing.
No errors or panics occurred, but the hashes were wrong. Nasty!
- func (t trackDigestReader) Read(p []byte) (n int, err error) {
- // the buffer p is blackHole
- n, err = t.r.Read(p)
- // p may be corrupted by another goroutine here,
- // between the Read above and the Write below
- t.h.Write(p[:n])
- return
- }
+```go
+func (t trackDigestReader) Read(p []byte) (n int, err error) {
+ // the buffer p is blackHole
+ n, err = t.r.Read(p)
+ // p may be corrupted by another goroutine here,
+ // between the Read above and the Write below
+ t.h.Write(p[:n])
+ return
+}
+```
The bug was finally
[fixed](/cl/7011047)
diff --git a/_content/blog/randv2.md b/_content/blog/randv2.md
index 8a2c986..84bff56 100644
--- a/_content/blog/randv2.md
+++ b/_content/blog/randv2.md
@@ -223,17 +223,19 @@
a random integer in the range [0, `n`).
{{raw `
- func (r *Rand) Int63n(n int64) int64 {
- if n <= 0 {
- panic("invalid argument to Int63n")
- }
- max := int64((1<<63 - 1) - (1<<63)%uint64(n))
- v := r.Int63()
- for v > max {
- v = r.Int63()
- }
- return v % n
+~~~go
+func (r *Rand) Int63n(n int64) int64 {
+ if n <= 0 {
+ panic("invalid argument to Int63n")
}
+ max := int64((1<<63 - 1) - (1<<63)%uint64(n))
+ v := r.Int63()
+ for v > max {
+ v = r.Int63()
+ }
+ return v % n
+}
+~~~
`}}
The actual conversion is easy: `v % n`.
@@ -416,11 +418,15 @@
In the old API, to create a random duration of up to 5 seconds,
it was necessary to write:
- d := time.Duration(rand.Int63n(int64(5*time.Second)))
+ ```go
+ d := time.Duration(rand.Int63n(int64(5*time.Second)))
+ ```
Using `N`, the equivalent code is:
- d := rand.N(5 * time.Second)
+ ```go
+ d := rand.N(5 * time.Second)
+ ```
`N` is only a top-level function; there is no `N` method on `rand.Rand`
because there are no generic methods in Go.
diff --git a/_content/blog/range-functions.md b/_content/blog/range-functions.md
index 9db549f..4ef11dc 100644
--- a/_content/blog/range-functions.md
+++ b/_content/blog/range-functions.md
@@ -27,7 +27,7 @@
For example, let's consider this very simple `Set` type, a generic
type implemented on top of a map.
-```
+```go
// Set holds a set of elements.
type Set[E comparable] struct {
m map[E]struct{}
@@ -42,7 +42,7 @@
Naturally a set type has a way to add elements and a way to check
whether elements are present. The details here don't matter.
-```
+```go
// Add adds an element to a set.
func (s *Set[E]) Add(v E) {
s.m[v] = struct{}{}
@@ -58,7 +58,7 @@
And among other things we will want a function to return the union of
two sets.
-```
+```go
// Union returns the union of two sets.
func Union[E comparable](s1, s2 *Set[E]) *Set[E] {
r := New[E]()
@@ -96,7 +96,7 @@
function.
Here if the function returns false, we stop calling it.
-```
+```go
func (s *Set[E]) Push(f func(E) bool) {
for v := range s.m {
if !f(v) {
@@ -117,7 +117,7 @@
elements of a set: you call `Push` with a function that does what you
want with the element.
-```
+```go
func PrintAllElementsPush[E comparable](s *Set[E]) {
s.Push(func(v E) bool {
fmt.Println(v)
@@ -147,36 +147,38 @@
no more values are needed.
{{raw `
- // Pull returns a next function that returns each
- // element of s with a bool for whether the value
- // is valid. The stop function should be called
- // when finished calling the next function.
- func (s *Set[E]) Pull() (func() (E, bool), func()) {
- ch := make(chan E)
- stopCh := make(chan bool)
+~~~go
+// Pull returns a next function that returns each
+// element of s with a bool for whether the value
+// is valid. The stop function should be called
+// when finished calling the next function.
+func (s *Set[E]) Pull() (func() (E, bool), func()) {
+ ch := make(chan E)
+ stopCh := make(chan bool)
- go func() {
- defer close(ch)
- for v := range s.m {
- select {
- case ch <- v:
- case <-stopCh:
- return
- }
+ go func() {
+ defer close(ch)
+ for v := range s.m {
+ select {
+ case ch <- v:
+ case <-stopCh:
+ return
}
- }()
-
- next := func() (E, bool) {
- v, ok := <-ch
- return v, ok
}
+ }()
- stop := func() {
- close(stopCh)
- }
-
- return next, stop
+ next := func() (E, bool) {
+ v, ok := <-ch
+ return v, ok
}
+
+ stop := func() {
+ close(stopCh)
+ }
+
+ return next, stop
+}
+~~~
`}}
Nothing in the standard library works exactly this way. Both
@@ -191,7 +193,7 @@
You call `Pull` to get a function, and you repeatedly call that
function in a for loop.
-```
+```go
func PrintAllElementsPull[E comparable](s *Set[E]) {
next, stop := s.Pull()
defer stop()
@@ -280,7 +282,7 @@
arguments and returns a bool; by convention, we call it the yield
function.
-```
+```go
func(yield func() bool)
func(yield func(V) bool)
@@ -306,7 +308,7 @@
The name `Seq` is short for sequence, as iterators loop through a
sequence of values.
-```
+```go
package iter
type Seq[V any] func(yield func(V) bool)
@@ -326,7 +328,7 @@
The return type of `All` is `iter.Seq[E]`, so we know that it returns
an iterator.
-```
+```go
// All is an iterator over the elements of s.
func (s *Set[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
@@ -362,7 +364,7 @@
code, the actual implementation of the iterator is pretty simple: call
yield with every element of the set, stopping if yield returns false.
-```
+```go
for v := range s.m {
if !yield(v) {
return
@@ -376,7 +378,7 @@
The for/range statement supports any iterator, and this shows how easy
that is to use.
-```
+```go
func PrintAllElements[E comparable](s *Set[E]) {
for v := range s.All() {
fmt.Println(v)
@@ -483,7 +485,7 @@
This function reports whether two arbitrary sequences contain the same
elements in the same order.
-```
+```go
// EqSeq reports whether two iterators contain the same
// elements in the same order.
func EqSeq[E comparable](s1, s2 iter.Seq[E]) bool {
@@ -539,7 +541,7 @@
The other argument is a filter function that decides which values
should be in the new iterator that `Filter` returns.
-```
+```go
// Filter returns a sequence that contains the elements
// of s for which f returns true.
func Filter[V any](f func(V) bool, s iter.Seq[V]) iter.Seq[V] {
@@ -560,7 +562,7 @@
Once you get past the signatures, the implementation is
straightforward.
-```
+```go
for v := range s {
if f(v) {
if !yield(v) {
@@ -584,7 +586,7 @@
As an example of how convenient a push iterator can be to loop over a
container type, let's consider this simple binary tree type.
-```
+```go
// Tree is a binary tree.
type Tree[E any] struct {
val E
@@ -601,7 +603,7 @@
the `All` method here returns a small function literal that calls the
iterator itself, here called `push`, and ignores the bool result.
-```
+```go
// All returns an iterator over the values in t.
func (t *Tree[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
@@ -673,7 +675,7 @@
This function takes a map from int to string and returns a slice
holding just the values in the map that are longer than some argument `n`.
-```
+```go
// LongStrings returns a slice of just the values
// in m whose length is n or more.
func LongStrings(m map[int]string, n int) []string {
@@ -708,7 +710,7 @@
the lines in a byte slice.
This is easy to write and fairly efficient.
-```
+```go
nl := []byte{'\n'}
// Trim a trailing newline to avoid a final empty blank line.
for _, line := range bytes.Split(bytes.TrimSuffix(data, nl), nl) {
@@ -727,7 +729,7 @@
We keep picking lines out of data until there is nothing left, and we
pass each line to the yield function.
-```
+```go
// Lines returns an iterator over lines in data.
func Lines(data []byte) iter.Seq[[]byte] {
return func(yield func([]byte) bool) {
@@ -744,7 +746,7 @@
Now our code to loop over the lines of a byte slice looks like this.
-```
+```go
for line := range Lines(data) {
handleLine(line)
}
@@ -768,7 +770,7 @@
our hand-written yield function.
-```
+```go
func PrintAllElements[E comparable](s *Set[E]) {
s.All()(func(v E) bool {
fmt.Println(v)
diff --git a/_content/blog/routing-enhancements.md b/_content/blog/routing-enhancements.md
index 8e3f5e1..7c4fede 100644
--- a/_content/blog/routing-enhancements.md
+++ b/_content/blog/routing-enhancements.md
@@ -35,7 +35,9 @@
ID 234. Before Go 1.22, the code for handling those requests would start with a
line like this:
- http.HandleFunc("/posts/", handlePost)
+```go
+http.HandleFunc("/posts/", handlePost)
+```
The trailing slash routes all requests beginning `/posts/` to the `handlePost`
function, which would have to check that the HTTP method was GET, extract
@@ -46,7 +48,9 @@
In Go 1.22, the existing code will continue to work, or you could instead write this:
- http.HandleFunc("GET /posts/{id}", handlePost2)
+```go
+http.HandleFunc("GET /posts/{id}", handlePost2)
+```
This pattern matches a GET request whose path begins "/posts/" and has two
segments. (As a special case, GET also matches HEAD; all the other methods match
@@ -54,7 +58,9 @@
extracting the identifier string can be written using the new `PathValue` method
on `Request`:
- idString := req.PathValue("id")
+```go
+idString := req.PathValue("id")
+```
The rest of `handlePost2` would behave like `handlePost`, converting the string
identifier to an integer and fetching the post.
diff --git a/_content/blog/slices-intro.md b/_content/blog/slices-intro.md
index 88c8ddc..e97d7f0 100644
--- a/_content/blog/slices-intro.md
+++ b/_content/blog/slices-intro.md
@@ -30,15 +30,19 @@
Arrays can be indexed in the usual way, so the expression `s[n]` accesses
the nth element, starting from zero.
- var a [4]int
- a[0] = 1
- i := a[0]
- // i == 1
+```go
+var a [4]int
+a[0] = 1
+i := a[0]
+// i == 1
+```
Arrays do not need to be initialized explicitly;
the zero value of an array is a ready-to-use array whose elements are themselves zeroed:
- // a[2] == 0, the zero value of the int type
+```go
+// a[2] == 0, the zero value of the int type
+```
The in-memory representation of `[4]int` is just four integer values laid out sequentially:
@@ -55,11 +59,15 @@
An array literal can be specified like so:
- b := [2]string{"Penn", "Teller"}
+```go
+b := [2]string{"Penn", "Teller"}
+```
Or, you can have the compiler count the array elements for you:
- b := [...]string{"Penn", "Teller"}
+```go
+b := [...]string{"Penn", "Teller"}
+```
In both cases, the type of `b` is `[2]string`.
@@ -75,30 +83,40 @@
A slice literal is declared just like an array literal, except you leave out the element count:
- letters := []string{"a", "b", "c", "d"}
+```go
+letters := []string{"a", "b", "c", "d"}
+```
A slice can be created with the built-in function called `make`, which has the signature,
- func make([]T, len, cap) []T
+```go
+func make([]T, len, cap) []T
+```
where T stands for the element type of the slice to be created.
The `make` function takes a type, a length,
and an optional capacity.
When called, `make` allocates an array and returns a slice that refers to that array.
- var s []byte
- s = make([]byte, 5, 5)
- // s == []byte{0, 0, 0, 0, 0}
+```go
+var s []byte
+s = make([]byte, 5, 5)
+// s == []byte{0, 0, 0, 0, 0}
+```
When the capacity argument is omitted, it defaults to the specified length.
Here's a more succinct version of the same code:
- s := make([]byte, 5)
+```go
+s := make([]byte, 5)
+```
The length and capacity of a slice can be inspected using the built-in `len` and `cap` functions.
- len(s) == 5
- cap(s) == 5
+```go
+len(s) == 5
+cap(s) == 5
+```
The next two sections discuss the relationship between length and capacity.
@@ -109,19 +127,25 @@
For example, the expression `b[1:4]` creates a slice including elements
1 through 3 of `b` (the indices of the resulting slice will be 0 through 2).
- b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
- // b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
+```go
+b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
+// b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
+```
The start and end indices of a slice expression are optional; they default to zero and the slice's length respectively:
- // b[:2] == []byte{'g', 'o'}
- // b[2:] == []byte{'l', 'a', 'n', 'g'}
- // b[:] == b
+```go
+// b[:2] == []byte{'g', 'o'}
+// b[2:] == []byte{'l', 'a', 'n', 'g'}
+// b[:] == b
+```
This is also the syntax to create a slice given an array:
- x := [3]string{"Лайка", "Белка", "Стрелка"}
- s := x[:] // a slice referencing the storage of x
+```go
+x := [3]string{"Лайка", "Белка", "Стрелка"}
+s := x[:] // a slice referencing the storage of x
+```
## Slice internals
@@ -143,7 +167,9 @@
As we slice `s`, observe the changes in the slice data structure and their relation to the underlying array:
- s = s[2:4]
+```go
+s = s[2:4]
+```
{{image "slices-intro/slice-2.png"}}
@@ -153,16 +179,20 @@
Therefore, modifying the _elements_ (not the slice itself) of a re-slice
modifies the elements of the original slice:
- d := []byte{'r', 'o', 'a', 'd'}
- e := d[2:]
- // e == []byte{'a', 'd'}
- e[1] = 'm'
- // e == []byte{'a', 'm'}
- // d == []byte{'r', 'o', 'a', 'm'}
+```go
+d := []byte{'r', 'o', 'a', 'd'}
+e := d[2:]
+// e == []byte{'a', 'd'}
+e[1] = 'm'
+// e == []byte{'a', 'm'}
+// d == []byte{'r', 'o', 'a', 'm'}
+```
Earlier we sliced `s` to a length shorter than its capacity. We can grow s to its capacity by slicing it again:
- s = s[:cap(s)]
+```go
+s = s[:cap(s)]
+```
{{image "slices-intro/slice-3.png"}}
@@ -181,17 +211,21 @@
`t`, copying the contents of `s` into `t`,
and then assigning the slice value `t` to `s`:
- t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
- for i := range s {
- t[i] = s[i]
- }
- s = t
+```go
+t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
+for i := range s {
+ t[i] = s[i]
+}
+s = t
+```
The looping piece of this common operation is made easier by the built-in copy function.
As the name suggests, copy copies data from a source slice to a destination slice.
It returns the number of elements copied.
- func copy(dst, src []T) int
+```go
+func copy(dst, src []T) int
+```
The `copy` function supports copying between slices of different lengths
(it will copy only up to the smaller number of elements).
@@ -201,33 +235,39 @@
Using `copy`, we can simplify the code snippet above:
- t := make([]byte, len(s), (cap(s)+1)*2)
- copy(t, s)
- s = t
+```go
+t := make([]byte, len(s), (cap(s)+1)*2)
+copy(t, s)
+s = t
+```
A common operation is to append data to the end of a slice.
This function appends byte elements to a slice of bytes,
growing the slice if necessary, and returns the updated slice value:
- func AppendByte(slice []byte, data ...byte) []byte {
- m := len(slice)
- n := m + len(data)
- if n > cap(slice) { // if necessary, reallocate
- // allocate double what's needed, for future growth.
- newSlice := make([]byte, (n+1)*2)
- copy(newSlice, slice)
- slice = newSlice
- }
- slice = slice[0:n]
- copy(slice[m:n], data)
- return slice
- }
+```go
+func AppendByte(slice []byte, data ...byte) []byte {
+ m := len(slice)
+ n := m + len(data)
+ if n > cap(slice) { // if necessary, reallocate
+ // allocate double what's needed, for future growth.
+ newSlice := make([]byte, (n+1)*2)
+ copy(newSlice, slice)
+ slice = newSlice
+ }
+ slice = slice[0:n]
+ copy(slice[m:n], data)
+ return slice
+}
+```
One could use `AppendByte` like this:
- p := []byte{2, 3, 5}
- p = AppendByte(p, 7, 11, 13)
- // p == []byte{2, 3, 5, 7, 11, 13}
+```go
+p := []byte{2, 3, 5}
+p = AppendByte(p, 7, 11, 13)
+// p == []byte{2, 3, 5, 7, 11, 13}
+```
Functions like `AppendByte` are useful because they offer complete control
over the way the slice is grown.
@@ -239,37 +279,45 @@
so Go provides a built-in `append` function that's good for most purposes;
it has the signature
- func append(s []T, x ...T) []T
+```go
+func append(s []T, x ...T) []T
+```
The `append` function appends the elements `x` to the end of the slice `s`,
and grows the slice if a greater capacity is needed.
- a := make([]int, 1)
- // a == []int{0}
- a = append(a, 1, 2, 3)
- // a == []int{0, 1, 2, 3}
+```go
+a := make([]int, 1)
+// a == []int{0}
+a = append(a, 1, 2, 3)
+// a == []int{0, 1, 2, 3}
+```
To append one slice to another, use `...` to expand the second argument to a list of arguments.
- a := []string{"John", "Paul"}
- b := []string{"George", "Ringo", "Pete"}
- a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"
- // a == []string{"John", "Paul", "George", "Ringo", "Pete"}
+```go
+a := []string{"John", "Paul"}
+b := []string{"George", "Ringo", "Pete"}
+a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"
+// a == []string{"John", "Paul", "George", "Ringo", "Pete"}
+```
Since the zero value of a slice (`nil`) acts like a zero-length slice,
you can declare a slice variable and then append to it in a loop:
- // Filter returns a new slice holding only
- // the elements of s that satisfy fn()
- func Filter(s []int, fn func(int) bool) []int {
- var p []int // == nil
- for _, v := range s {
- if fn(v) {
- p = append(p, v)
- }
- }
- return p
- }
+```go
+// Filter returns a new slice holding only
+// the elements of s that satisfy fn()
+func Filter(s []int, fn func(int) bool) []int {
+ var p []int // == nil
+ for _, v := range s {
+ if fn(v) {
+ p = append(p, v)
+ }
+ }
+ return p
+}
+```
## A possible "gotcha"
@@ -282,12 +330,14 @@
it for the first group of consecutive numeric digits,
returning them as a new slice.
- var digitRegexp = regexp.MustCompile("[0-9]+")
+```go
+var digitRegexp = regexp.MustCompile("[0-9]+")
- func FindDigits(filename string) []byte {
- b, _ := ioutil.ReadFile(filename)
- return digitRegexp.Find(b)
- }
+func FindDigits(filename string) []byte {
+ b, _ := ioutil.ReadFile(filename)
+ return digitRegexp.Find(b)
+}
+```
This code behaves as advertised, but the returned `[]byte` points into an
array containing the entire file.
@@ -297,13 +347,15 @@
To fix this problem one can copy the interesting data to a new slice before returning it:
- func CopyDigits(filename string) []byte {
- b, _ := ioutil.ReadFile(filename)
- b = digitRegexp.Find(b)
- c := make([]byte, len(b))
- copy(c, b)
- return c
- }
+```go
+func CopyDigits(filename string) []byte {
+ b, _ := ioutil.ReadFile(filename)
+ b = digitRegexp.Find(b)
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+```
A more concise version of this function could be constructed by using `append`.
This is left as an exercise for the reader.
diff --git a/_content/blog/slices.md b/_content/blog/slices.md
index 03f5539..664a0f8 100644
--- a/_content/blog/slices.md
+++ b/_content/blog/slices.md
@@ -99,11 +99,15 @@
`buffer`, by slicing elements 100 (inclusive) through 150 (exclusive).
The more idiomatic syntax would drop the type, which is set by the initializing expression:
- var slice = buffer[100:150]
+```go
+var slice = buffer[100:150]
+```
Inside a function we could use the short declaration form,
- slice := buffer[100:150]
+```go
+slice := buffer[100:150]
+```
What exactly is this slice variable?
It's not quite the full story, but for now think of a
@@ -111,15 +115,17 @@
of an array.
You can think of it as being built like this behind the scenes:
- type sliceHeader struct {
- Length int
- ZerothElement *byte
- }
+```go
+type sliceHeader struct {
+ Length int
+ ZerothElement *byte
+}
- slice := sliceHeader{
- Length: 50,
- ZerothElement: &buffer[100],
- }
+slice := sliceHeader{
+ Length: 50,
+ ZerothElement: &buffer[100],
+}
+```
Of course, this is just an illustration.
Despite what this snippet says that `sliceHeader` struct is not visible
@@ -129,7 +135,9 @@
So far we've used a slice operation on an array, but we can also slice a slice, like this:
- slice2 := slice[5:10]
+```go
+slice2 := slice[5:10]
+```
Just as before, this operation creates a new slice, in this case with elements
5 through 9 (inclusive) of the original slice, which means elements
@@ -137,10 +145,12 @@
The underlying `sliceHeader` struct for the `slice2` variable looks like
this:
- slice2 := sliceHeader{
- Length: 5,
- ZerothElement: &buffer[105],
- }
+```go
+slice2 := sliceHeader{
+ Length: 5,
+ ZerothElement: &buffer[105],
+}
+```
Notice that this header still points to the same underlying array, stored in
the `buffer` variable.
@@ -148,14 +158,18 @@
We can also _reslice_, which is to say slice a slice and store the result back in
the original slice structure. After
- slice = slice[5:10]
+```go
+slice = slice[5:10]
+```
the `sliceHeader` structure for the `slice` variable looks just like it did for the `slice2`
variable.
You'll see reslicing used often, for example to truncate a slice. This statement drops
the first and last elements of our slice:
- slice = slice[1:len(slice)-1]
+```go
+slice = slice[1:len(slice)-1]
+```
[Exercise: Write out what the `sliceHeader` struct looks like after this assignment.]
@@ -166,7 +180,9 @@
what gets passed to the function.
In this call,
- slashPos := bytes.IndexRune(slice, '/')
+```go
+slashPos := bytes.IndexRune(slice, '/')
+```
the `slice` argument that is passed to the `IndexRune` function is, in fact,
a "slice header".
@@ -272,11 +288,13 @@
It's time to talk about the third component of the slice header: its _capacity_.
Besides the array pointer and length, the slice header also stores its capacity:
- type sliceHeader struct {
- Length int
- Capacity int
- ZerothElement *byte
- }
+```go
+type sliceHeader struct {
+ Length int
+ Capacity int
+ ZerothElement *byte
+}
+```
The `Capacity` field records how much space the underlying array actually has; it is the maximum
value the `Length` can reach.
@@ -284,23 +302,29 @@
After our example slice is created by
- slice := iBuffer[0:0]
+```go
+slice := iBuffer[0:0]
+```
its header looks like this:
- slice := sliceHeader{
- Length: 0,
- Capacity: 10,
- ZerothElement: &iBuffer[0],
- }
+```go
+slice := sliceHeader{
+ Length: 0,
+ Capacity: 10,
+ ZerothElement: &iBuffer[0],
+}
+```
The `Capacity` field is equal to the length of the underlying array,
minus the index in the array of the first element of the slice (zero in this case).
If you want to inquire what the capacity is for a slice, use the built-in function `cap`:
- if cap(slice) == len(slice) {
- fmt.Println("slice is full!")
- }
+```go
+if cap(slice) == len(slice) {
+ fmt.Println("slice is full!")
+}
+```
## Make
@@ -334,7 +358,9 @@
to set them both to the same value.
After
- gophers := make([]Gopher, 10)
+```go
+gophers := make([]Gopher, 10)
+```
the `gophers` slice has both its length and capacity set to 10.
@@ -365,21 +391,29 @@
Second, it uses a convenient shorthand.
The expression
- slice[i:]
+```go
+slice[i:]
+```
means exactly the same as
- slice[i:len(slice)]
+```go
+slice[i:len(slice)]
+```
Also, although we haven't used the trick yet, we can leave out the first element of a slice expression too;
it defaults to zero. Thus
- slice[:]
+```go
+slice[:]
+```
just means the slice itself, which is useful when slicing an array.
This expression is the shortest way to say "a slice describing all the elements of the array":
- array[:]
+```go
+array[:]
+```
Now that's out of the way, let's run our `Insert` function.
@@ -415,7 +449,9 @@
For the first version, we can just call `Extend` repeatedly so the mechanism of the variadic function is clear.
The signature of `Append` is this:
- func Append(slice []int, items ...int) []int
+```go
+func Append(slice []int, items ...int) []int
+```
What that says is that `Append` takes one argument, a slice, followed by zero or more
`int` arguments.
@@ -485,19 +521,25 @@
As an aside, with our newfound knowledge we can see what the representation of a `nil` slice is.
Naturally, it is the zero value of the slice header:
- sliceHeader{
- Length: 0,
- Capacity: 0,
- ZerothElement: nil,
- }
+```go
+sliceHeader{
+ Length: 0,
+ Capacity: 0,
+ ZerothElement: nil,
+}
+```
or just
- sliceHeader{}
+```go
+sliceHeader{}
+```
The key detail is that the element pointer is `nil` too. The slice created by
- array[0:0]
+```go
+array[0:0]
+```
has length zero (and maybe even capacity zero) but its pointer is not `nil`, so
it is not a nil slice.
@@ -524,21 +566,29 @@
For starters, we can index them to access individual bytes:
- slash := "/usr/ken"[0] // yields the byte value '/'.
+```go
+slash := "/usr/ken"[0] // yields the byte value '/'.
+```
We can slice a string to grab a substring:
- usr := "/usr/ken"[0:4] // yields the string "/usr"
+```go
+usr := "/usr/ken"[0:4] // yields the string "/usr"
+```
It should be obvious now what's going on behind the scenes when we slice a string.
We can also take a normal slice of bytes and create a string from it with the simple conversion:
- str := string(slice)
+```go
+str := string(slice)
+```
and go in the reverse direction as well:
- slice := []byte(usr)
+```go
+slice := []byte(usr)
+```
The array underlying a string is hidden from view; there is no way to access its contents
except through the string. That means that when we do either of these conversions, a
diff --git a/_content/blog/slog.md b/_content/blog/slog.md
index ce94566..2172c35 100644
--- a/_content/blog/slog.md
+++ b/_content/blog/slog.md
@@ -34,7 +34,7 @@
Here is the simplest program that uses `slog`:
-```
+```go
package main
import "log/slog"
@@ -64,7 +64,7 @@
Unlike with the `log` package, we can easily add key-value pairs to our output
by writing them after the message:
-```
+```go
slog.Info("hello, world", "user", os.Getenv("USER"))
```
@@ -75,7 +75,7 @@
As we mentioned, `slog`'s top-level functions use the default logger.
We can get this logger explicitly, and call its methods:
-```
+```go
logger := slog.Default()
logger.Info("hello, world", "user", os.Getenv("USER"))
```
@@ -91,7 +91,7 @@
This program creates a new logger using a `TextHandler` and
makes the same call to the `Info` method:
-```
+```go
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("hello, world", "user", os.Getenv("USER"))
```
@@ -104,7 +104,7 @@
For JSON output, install the built-in `JSONHandler` instead:
-```
+```go
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("hello, world", "user", os.Getenv("USER"))
```
@@ -126,7 +126,7 @@
There are functions for building `Attr`s out of strings, numbers, and other common
types. This call to `LogAttrs` produces the same output as above, but does it faster:
-```
+```go
slog.LogAttrs(context.Background(), slog.LevelInfo, "hello, world",
slog.String("user", os.Getenv("USER")))
```
@@ -239,13 +239,17 @@
One change we did not make concerned the alternating key-and-value syntax for
expressing attributes:
- slog.Info("message", "k1", v1, "k2", v2)
+```go
+slog.Info("message", "k1", v1, "k2", v2)
+```
Many felt strongly that this was a bad idea. They found it hard to read
and easy to get wrong by omitting a key or value. They preferred explicit
attributes for expressing structure:
- slog.Info("message", slog.Int("k1", v1), slog.String("k2", v2))
+```go
+slog.Info("message", slog.Int("k1", v1), slog.String("k2", v2))
+```
But we felt that the lighter syntax was important to keeping Go easy and fun to
use, especially for new Go programmers. We also knew that several Go logging
diff --git a/_content/blog/strings.md b/_content/blog/strings.md
index accd034..e243beb 100644
--- a/_content/blog/strings.md
+++ b/_content/blog/strings.md
@@ -189,7 +189,9 @@
Source code in Go is _defined_ to be UTF-8 text; no other representation is
allowed. That implies that when, in the source code, we write the text
- `⌘`
+```go
+`⌘`
+```
the text editor used to create the program places the UTF-8 encoding
of the symbol ⌘ into the source text.
@@ -258,7 +260,9 @@
_rune constant_ in Go.
The type and value of the expression
- '⌘'
+```go
+'⌘'
+```
is `rune` with integer value `0x2318`.
diff --git a/_content/blog/subtests.md b/_content/blog/subtests.md
index 3ece61a..5173393 100644
--- a/_content/blog/subtests.md
+++ b/_content/blog/subtests.md
@@ -30,27 +30,29 @@
A series of related checks can be implemented by looping over a slice of test
cases:
- func TestTime(t *testing.T) {
- testCases := []struct {
- gmt string
- loc string
- want string
- }{
- {"12:31", "Europe/Zuri", "13:31"}, // incorrect location name
- {"12:31", "America/New_York", "7:31"}, // should be 07:31
- {"08:08", "Australia/Sydney", "18:08"},
+```go
+func TestTime(t *testing.T) {
+ testCases := []struct {
+ gmt string
+ loc string
+ want string
+ }{
+ {"12:31", "Europe/Zuri", "13:31"}, // incorrect location name
+ {"12:31", "America/New_York", "7:31"}, // should be 07:31
+ {"08:08", "Australia/Sydney", "18:08"},
+ }
+ for _, tc := range testCases {
+ loc, err := time.LoadLocation(tc.loc)
+ if err != nil {
+ t.Fatalf("could not load location %q", tc.loc)
}
- for _, tc := range testCases {
- loc, err := time.LoadLocation(tc.loc)
- if err != nil {
- t.Fatalf("could not load location %q", tc.loc)
- }
- gmt, _ := time.Parse("15:04", tc.gmt)
- if got := gmt.In(loc).Format("15:04"); got != tc.want {
- t.Errorf("In(%s, %s) = %s; want %s", tc.gmt, tc.loc, got, tc.want)
- }
+ gmt, _ := time.Parse("15:04", tc.gmt)
+ if got := gmt.In(loc).Format("15:04"); got != tc.want {
+ t.Errorf("In(%s, %s) = %s; want %s", tc.gmt, tc.loc, got, tc.want)
}
}
+}
+```
This approach, commonly referred to as table-driven tests, reduces the amount
of repetitive code compared to repeating the same code for each test
@@ -69,50 +71,54 @@
looked something like this:
{{raw `
- func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) {
- dst := make([]byte, 30)
- b.ResetTimer() // Overkill here, but for illustrative purposes.
- for i := 0; i < b.N; i++ {
- AppendFloat(dst[:0], f, fmt, prec, bitSize)
- }
+~~~go
+func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) {
+ dst := make([]byte, 30)
+ b.ResetTimer() // Overkill here, but for illustrative purposes.
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst[:0], f, fmt, prec, bitSize)
}
+}
- func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) }
- func BenchmarkAppendFloat(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) }
- func BenchmarkAppendFloatExp(b *testing.B) { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) }
- func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) }
- func BenchmarkAppendFloatBig(b *testing.B) { benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) }
- ...
+func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) }
+func BenchmarkAppendFloat(b *testing.B) { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) }
+func BenchmarkAppendFloatExp(b *testing.B) { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) }
+func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) }
+func BenchmarkAppendFloatBig(b *testing.B) { benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) }
+...
+~~~
`}}
Using the `Run` method available in Go 1.7, the same set of benchmarks is now
expressed as a single top-level benchmark:
{{raw `
- func BenchmarkAppendFloat(b *testing.B) {
- benchmarks := []struct{
- name string
- float float64
- fmt byte
- prec int
- bitSize int
- }{
- {"Decimal", 33909, 'g', -1, 64},
- {"Float", 339.7784, 'g', -1, 64},
- {"Exp", -5.09e75, 'g', -1, 64},
- {"NegExp", -5.11e-95, 'g', -1, 64},
- {"Big", 123456789123456789123456789, 'g', -1, 64},
- ...
- }
- dst := make([]byte, 30)
- for _, bm := range benchmarks {
- b.Run(bm.name, func(b *testing.B) {
- for i := 0; i < b.N; i++ {
- AppendFloat(dst[:0], bm.float, bm.fmt, bm.prec, bm.bitSize)
- }
- })
- }
+~~~go
+func BenchmarkAppendFloat(b *testing.B) {
+ benchmarks := []struct{
+ name string
+ float float64
+ fmt byte
+ prec int
+ bitSize int
+ }{
+ {"Decimal", 33909, 'g', -1, 64},
+ {"Float", 339.7784, 'g', -1, 64},
+ {"Exp", -5.09e75, 'g', -1, 64},
+ {"NegExp", -5.11e-95, 'g', -1, 64},
+ {"Big", 123456789123456789123456789, 'g', -1, 64},
+ ...
}
+ dst := make([]byte, 30)
+ for _, bm := range benchmarks {
+ b.Run(bm.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst[:0], bm.float, bm.fmt, bm.prec, bm.bitSize)
+ }
+ })
+ }
+}
+~~~
`}}
Each invocation of the `Run` method creates a separate benchmark.
@@ -129,29 +135,31 @@
Go 1.7 also introduces a `Run` method for creating subtests.
This test is a rewritten version of our earlier example using subtests:
- func TestTime(t *testing.T) {
- testCases := []struct {
- gmt string
- loc string
- want string
- }{
- {"12:31", "Europe/Zuri", "13:31"},
- {"12:31", "America/New_York", "7:31"},
- {"08:08", "Australia/Sydney", "18:08"},
- }
- for _, tc := range testCases {
- t.Run(fmt.Sprintf("%s in %s", tc.gmt, tc.loc), func(t *testing.T) {
- loc, err := time.LoadLocation(tc.loc)
- if err != nil {
- t.Fatal("could not load location")
- }
- gmt, _ := time.Parse("15:04", tc.gmt)
- if got := gmt.In(loc).Format("15:04"); got != tc.want {
- t.Errorf("got %s; want %s", got, tc.want)
- }
- })
- }
+```go
+func TestTime(t *testing.T) {
+ testCases := []struct {
+ gmt string
+ loc string
+ want string
+ }{
+ {"12:31", "Europe/Zuri", "13:31"},
+ {"12:31", "America/New_York", "7:31"},
+ {"08:08", "Australia/Sydney", "18:08"},
}
+ for _, tc := range testCases {
+ t.Run(fmt.Sprintf("%s in %s", tc.gmt, tc.loc), func(t *testing.T) {
+ loc, err := time.LoadLocation(tc.loc)
+ if err != nil {
+ t.Fatal("could not load location")
+ }
+ gmt, _ := time.Parse("15:04", tc.gmt)
+ if got := gmt.In(loc).Format("15:04"); got != tc.want {
+ t.Errorf("got %s; want %s", got, tc.want)
+ }
+ })
+ }
+}
+```
The first thing to note is the difference in output from the two implementations.
The original implementation prints:
@@ -252,17 +260,19 @@
Subtests and sub-benchmarks can be used to manage common setup and tear-down code:
{{raw `
- func TestFoo(t *testing.T) {
- // <setup code>
- t.Run("A=1", func(t *testing.T) { ... })
- t.Run("A=2", func(t *testing.T) { ... })
- t.Run("B=1", func(t *testing.T) {
- if !test(foo{B:1}) {
- t.Fail()
- }
- })
- // <tear-down code>
- }
+~~~go
+func TestFoo(t *testing.T) {
+ // <setup code>
+ t.Run("A=1", func(t *testing.T) { ... })
+ t.Run("A=2", func(t *testing.T) { ... })
+ t.Run("B=1", func(t *testing.T) {
+ if !test(foo{B:1}) {
+ t.Fail()
+ }
+ })
+ // <tear-down code>
+}
+~~~
`}}
The setup and tear-down code will run if any of the enclosed subtests are run
@@ -298,18 +308,20 @@
The above semantics allows for running a group of tests in parallel with
each other but not with other parallel tests:
- func TestGroupedParallel(t *testing.T) {
- for _, tc := range testCases {
- tc := tc // capture range variable
- t.Run(tc.Name, func(t *testing.T) {
- t.Parallel()
- if got := foo(tc.in); got != tc.out {
- t.Errorf("got %v; want %v", got, tc.out)
- }
- ...
- })
- }
+```go
+func TestGroupedParallel(t *testing.T) {
+ for _, tc := range testCases {
+ tc := tc // capture range variable
+ t.Run(tc.Name, func(t *testing.T) {
+ t.Parallel()
+ if got := foo(tc.in); got != tc.out {
+ t.Errorf("got %v; want %v", got, tc.out)
+ }
+ ...
+ })
}
+}
+```
The outer test will not complete until all parallel tests started by `Run`
have completed.
@@ -326,16 +338,18 @@
that share common resources:
{{raw `
- func TestTeardownParallel(t *testing.T) {
- // <setup code>
- // This Run will not return until its parallel subtests complete.
- t.Run("group", func(t *testing.T) {
- t.Run("Test1", parallelTest1)
- t.Run("Test2", parallelTest2)
- t.Run("Test3", parallelTest3)
- })
- // <tear-down code>
- }
+~~~go
+func TestTeardownParallel(t *testing.T) {
+ // <setup code>
+ // This Run will not return until its parallel subtests complete.
+ t.Run("group", func(t *testing.T) {
+ t.Run("Test1", parallelTest1)
+ t.Run("Test2", parallelTest2)
+ t.Run("Test3", parallelTest3)
+ })
+ // <tear-down code>
+}
+~~~
`}}
The behavior of waiting on a group of parallel tests is identical to that
diff --git a/_content/blog/synctest.md b/_content/blog/synctest.md
index 6b4f9cd..ce503bb 100644
--- a/_content/blog/synctest.md
+++ b/_content/blog/synctest.md
@@ -35,20 +35,22 @@
Here is a possible test for `AfterFunc`:
{{raw `
- func TestAfterFunc(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
+~~~go
+func TestAfterFunc(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
- calledCh := make(chan struct{}) // closed when AfterFunc is called
- context.AfterFunc(ctx, func() {
- close(calledCh)
- })
+ calledCh := make(chan struct{}) // closed when AfterFunc is called
+ context.AfterFunc(ctx, func() {
+ close(calledCh)
+ })
- // TODO: Assert that the AfterFunc has not been called.
+ // TODO: Assert that the AfterFunc has not been called.
- cancel()
+ cancel()
- // TODO: Assert that the AfterFunc has been called.
- }
+ // TODO: Assert that the AfterFunc has been called.
+}
+~~~
`}}
We want to check two conditions in this test:
@@ -64,25 +66,27 @@
Let's try introducing a helper function to our test which does this.
{{raw `
- // funcCalled reports whether the function was called.
- funcCalled := func() bool {
- select {
- case <-calledCh:
- return true
- case <-time.After(10 * time.Millisecond):
- return false
- }
+~~~go
+// funcCalled reports whether the function was called.
+funcCalled := func() bool {
+ select {
+ case <-calledCh:
+ return true
+ case <-time.After(10 * time.Millisecond):
+ return false
}
+}
- if funcCalled() {
- t.Fatalf("AfterFunc function called before context is canceled")
- }
+if funcCalled() {
+ t.Fatalf("AfterFunc function called before context is canceled")
+}
- cancel()
+cancel()
- if !funcCalled() {
- t.Fatalf("AfterFunc function not called after context is canceled")
- }
+if !funcCalled() {
+ t.Fatalf("AfterFunc function not called after context is canceled")
+}
+~~~
`}}
This test is slow:
@@ -116,28 +120,30 @@
Let's rewrite our test above using the `testing/synctest` package.
{{raw `
- func TestAfterFunc(t *testing.T) {
- synctest.Run(func() {
- ctx, cancel := context.WithCancel(context.Background())
+~~~go
+func TestAfterFunc(t *testing.T) {
+ synctest.Run(func() {
+ ctx, cancel := context.WithCancel(context.Background())
- funcCalled := false
- context.AfterFunc(ctx, func() {
- funcCalled = true
- })
-
- synctest.Wait()
- if funcCalled {
- t.Fatalf("AfterFunc function called before context is canceled")
- }
-
- cancel()
-
- synctest.Wait()
- if !funcCalled {
- t.Fatalf("AfterFunc function not called after context is canceled")
- }
+ funcCalled := false
+ context.AfterFunc(ctx, func() {
+ funcCalled = true
})
- }
+
+ synctest.Wait()
+ if funcCalled {
+ t.Fatalf("AfterFunc function called before context is canceled")
+ }
+
+ cancel()
+
+ synctest.Wait()
+ if !funcCalled {
+ t.Fatalf("AfterFunc function not called after context is canceled")
+ }
+ })
+}
+~~~
`}}
This is almost identical to our original test,
@@ -185,27 +191,29 @@
which expires after a given timeout.
{{raw `
- func TestWithTimeout(t *testing.T) {
- synctest.Run(func() {
- const timeout = 5 * time.Second
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
+~~~go
+func TestWithTimeout(t *testing.T) {
+ synctest.Run(func() {
+ const timeout = 5 * time.Second
+ ctx, cancel := context.WithTimeout(context.Background(), timeout)
+ defer cancel()
- // Wait just less than the timeout.
- time.Sleep(timeout - time.Nanosecond)
- synctest.Wait()
- if err := ctx.Err(); err != nil {
- t.Fatalf("before timeout, ctx.Err() = %v; want nil", err)
- }
+ // Wait just less than the timeout.
+ time.Sleep(timeout - time.Nanosecond)
+ synctest.Wait()
+ if err := ctx.Err(); err != nil {
+ t.Fatalf("before timeout, ctx.Err() = %v; want nil", err)
+ }
- // Wait the rest of the way until the timeout.
- time.Sleep(time.Nanosecond)
- synctest.Wait()
- if err := ctx.Err(); err != context.DeadlineExceeded {
- t.Fatalf("after timeout, ctx.Err() = %v; want DeadlineExceeded", err)
- }
- })
- }
+ // Wait the rest of the way until the timeout.
+ time.Sleep(time.Nanosecond)
+ synctest.Wait()
+ if err := ctx.Err(); err != context.DeadlineExceeded {
+ t.Fatalf("after timeout, ctx.Err() = %v; want DeadlineExceeded", err)
+ }
+ })
+}
+~~~
`}}
We write this test just as if we were working with real time.
@@ -319,47 +327,53 @@
an in-memory network connection created by [`net.Pipe`](/pkg/net#Pipe).
{{raw `
- func Test(t *testing.T) {
- synctest.Run(func() {
- srvConn, cliConn := net.Pipe()
- defer srvConn.Close()
- defer cliConn.Close()
- tr := &http.Transport{
- DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
- return cliConn, nil
- },
- // Setting a non-zero timeout enables "Expect: 100-continue" handling.
- // Since the following test does not sleep,
- // we will never encounter this timeout,
- // even if the test takes a long time to run on a slow machine.
- ExpectContinueTimeout: 5 * time.Second,
- }
+~~~go
+func Test(t *testing.T) {
+ synctest.Run(func() {
+ srvConn, cliConn := net.Pipe()
+ defer srvConn.Close()
+ defer cliConn.Close()
+ tr := &http.Transport{
+ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
+ return cliConn, nil
+ },
+ // Setting a non-zero timeout enables "Expect: 100-continue" handling.
+ // Since the following test does not sleep,
+ // we will never encounter this timeout,
+ // even if the test takes a long time to run on a slow machine.
+ ExpectContinueTimeout: 5 * time.Second,
+ }
+~~~
`}}
We send a request on this transport with the "Expect: 100-continue" header set.
The request is sent in a new goroutine, since it won't complete until the end of the test.
{{raw `
- body := "request body"
- go func() {
- req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body))
- req.Header.Set("Expect", "100-continue")
- resp, err := tr.RoundTrip(req)
- if err != nil {
- t.Errorf("RoundTrip: unexpected error %v", err)
- } else {
- resp.Body.Close()
- }
- }()
+~~~go
+ body := "request body"
+ go func() {
+ req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body))
+ req.Header.Set("Expect", "100-continue")
+ resp, err := tr.RoundTrip(req)
+ if err != nil {
+ t.Errorf("RoundTrip: unexpected error %v", err)
+ } else {
+ resp.Body.Close()
+ }
+ }()
+~~~
`}}
We read the request headers sent by the client.
{{raw `
- req, err := http.ReadRequest(bufio.NewReader(srvConn))
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
+~~~go
+ req, err := http.ReadRequest(bufio.NewReader(srvConn))
+ if err != nil {
+ t.Fatalf("ReadRequest: %v", err)
+ }
+~~~
`}}
Now we come to the heart of the test.
@@ -373,23 +387,27 @@
about a data race, but with the `Wait` this is safe.
{{raw `
- var gotBody strings.Builder
- go io.Copy(&gotBody, req.Body)
- synctest.Wait()
- if got := gotBody.String(); got != "" {
- t.Fatalf("before sending 100 Continue, unexpectedly read body: %q", got)
- }
+~~~go
+ var gotBody strings.Builder
+ go io.Copy(&gotBody, req.Body)
+ synctest.Wait()
+ if got := gotBody.String(); got != "" {
+ t.Fatalf("before sending 100 Continue, unexpectedly read body: %q", got)
+ }
+~~~
`}}
We write a "100 Continue" response to the client and verify that it now sends the
request body.
{{raw `
- srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))
- synctest.Wait()
- if got := gotBody.String(); got != body {
- t.Fatalf("after sending 100 Continue, read body %q, want %q", got, body)
- }
+~~~go
+ srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))
+ synctest.Wait()
+ if got := gotBody.String(); got != body {
+ t.Fatalf("after sending 100 Continue, read body %q, want %q", got, body)
+ }
+~~~
`}}
And finally, we finish up by sending the "200 OK" response to conclude the request.
@@ -398,9 +416,11 @@
The `synctest.Run` call will wait for all of them to exit before returning.
{{raw `
- srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
- })
- }
+~~~go
+ srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
+ })
+}
+~~~
`}}
This test can be easily extended to test other behaviors,
diff --git a/_content/blog/testing-b-loop.md b/_content/blog/testing-b-loop.md
index 6143bb6..7c9089c 100644
--- a/_content/blog/testing-b-loop.md
+++ b/_content/blog/testing-b-loop.md
@@ -17,7 +17,7 @@
[`testing.B.Loop`](https://pkg.go.dev/testing#B.Loop).
Traditionally, Go benchmarks are written using a loop from 0 to `b.N`:
-```
+```go
func Benchmark(b *testing.B) {
for range b.N {
... code to measure ...
@@ -25,7 +25,7 @@
}
```
Using `b.Loop` instead is a trivial change:
-```
+```go
func Benchmark(b *testing.B) {
for b.Loop() {
... code to measure ...
@@ -49,7 +49,7 @@
Before Go 1.24, while the basic structure of a benchmark was simple, more sophisticated
benchmarks required more care:
-```
+```go
func Benchmark(b *testing.B) {
... setup ...
b.ResetTimer() // if setup may be expensive
@@ -75,7 +75,7 @@
There is another, more subtle pitfall that requires deeper understanding:
([Example source](https://eli.thegreenplace.net/2023/common-pitfalls-in-go-benchmarking/))
-```
+```go
func isCond(b byte) bool {
if b%3 == 1 && b%7 == 2 && b%17 == 11 && b%31 == 9 {
return true
@@ -121,7 +121,7 @@
when necessary:
([Example source](https://eli.thegreenplace.net/2023/common-pitfalls-in-go-benchmarking/))
-```
+```go
func BenchmarkSortInts(b *testing.B) {
ints := make([]int, N)
for b.Loop() {
@@ -143,7 +143,7 @@
## When to use
The `testing.B.Loop` method is now the preferred way to write benchmarks:
-```
+```go
func Benchmark(b *testing.B) {
... setup ...
for b.Loop() {
diff --git a/_content/blog/testing-time.md b/_content/blog/testing-time.md
index 6b18c95..183cf40 100644
--- a/_content/blog/testing-time.md
+++ b/_content/blog/testing-time.md
@@ -35,7 +35,7 @@
the following `Cleanup` function is synchronous.
You call it, it deletes a cache directory, and it returns.
-```
+```go
func (c *Cache) Cleanup() {
os.RemoveAll(c.cacheDir)
}
@@ -44,7 +44,7 @@
`CleanupInBackground` is an asynchronous function.
You call it, it returns, and the cache directory is deleted...sooner or later.
-```
+```go
func (c *Cache) CleanupInBackground() {
go os.RemoveAll(c.cacheDir)
}
@@ -54,7 +54,7 @@
For example, the `context` package's `WithDeadline` function
returns a context which will be canceled in the future.
-```
+```go
package context
// WithDeadline returns a derived context
@@ -106,7 +106,7 @@
let's work with a real-world example.
Consider the `context` package's `WithDeadline` function again.
-```
+```go
package context
// WithDeadline returns a derived context
@@ -125,7 +125,7 @@
we'll just test the second case:
After the deadline expires, the context is canceled.
-```
+```go
func TestWithDeadlineAfterDeadline(t *testing.T) {
deadline := time.Now().Add(1 * time.Second)
ctx, _ := context.WithDeadline(t.Context(), deadline)
@@ -151,7 +151,7 @@
Let's fix it.
-```
+```go
time.Sleep(time.Until(deadline) + 100*time.Millisecond)
```
@@ -203,7 +203,7 @@
the higher up the call stack you can push your concurrency,
the better.
-```
+```go
// CleanupInBackground is hard to test.
cache.CleanupInBackground()
@@ -222,7 +222,7 @@
Here's an example of what this might look like for our `WithDeadline` test:
-```
+```go
func TestWithDeadlineAfterDeadline(t *testing.T) {
clock := fakeClock()
timeout := 1 * time.Second
@@ -252,7 +252,7 @@
I've added a `context.WithDeadlineClock` function here,
that takes an additional clock parameter:
-```
+```go
ctx, _ := context.WithDeadlineClock(
t.Context(), deadline, clock)
```
@@ -268,7 +268,7 @@
I've added a `context.WaitUntilIdle` function here,
which waits for any background work related to a context to complete:
-```
+```go
clock.Advance(timeout)
context.WaitUntilIdle(ctx)
```
@@ -421,7 +421,7 @@
The `synctest` package contains just two functions.
-```
+```go
package synctest
// Test executes f in a new bubble.
@@ -442,7 +442,7 @@
Let's look at an example of synctest in action.
-```
+```go
func TestWithDeadlineAfterDeadline(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
deadline := time.Now().Add(1 * time.Second)
@@ -484,7 +484,7 @@
If you need to run a test at some specific point in time for some reason,
you can just sleep until then.
-```
+```go
func TestAtSpecificTime(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
// 2000-01-01 00:00:00 +0000 UTC
@@ -508,7 +508,7 @@
of fake time have elapsed since the start of the test,
no matter how much real time has passed.
-```
+```go
func TestExpensiveWork(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
start := time.Now()
@@ -525,7 +525,7 @@
The test will always print that exactly ten fake seconds
have passed since the start of the test.
-```
+```go
func TestSleep(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
start := time.Now()
@@ -540,7 +540,7 @@
The [`synctest.Wait`](/pkg/testing/synctest#Wait) function
lets us wait for background activity to complete.
-```
+```go
func TestWait(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
done := false
@@ -580,7 +580,7 @@
the race detector will still report the data race,
just like it would if this code were run outside a synctest bubble.
-```
+```go
func TestTimeDataRace(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
done := false
@@ -598,7 +598,7 @@
Adding a `Wait` call provides explicit synchronization and fixes the data race:
-```
+```go
time.Sleep(1 * time.Nanosecond)
synctest.Wait() // synchronize
t.Log(done) // read
@@ -611,7 +611,7 @@
For example, consider this test of [`io.Copy`](/pkg/io#Copy).
-```
+```go
func TestIOCopy(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
srcReader, srcWriter := io.Pipe()
@@ -646,7 +646,7 @@
Looking at the test step by step,
we first create an `io.Pipe` to serve as the source `io.Copy` reads from:
-```
+```go
srcReader, srcWriter := io.Pipe()
defer srcWriter.Close()
```
@@ -654,7 +654,7 @@
We call `io.Copy` in a new goroutine,
copying from the read end of the pipe into a `bytes.Buffer`:
-```
+```go
var dst bytes.Buffer
go io.Copy(&dst, srcReader)
```
@@ -662,7 +662,7 @@
We write to the other end of the pipe,
and wait for `io.Copy` to handle the data:
-```
+```go
data := "1234"
srcWriter.Write([]byte("1234"))
synctest.Wait()
@@ -670,7 +670,7 @@
Finally, we verify that the destination buffer contains the desired data:
-```
+```go
if got, want := dst.String(), data; got != want {
t.Errorf("Copy wrote %q, want %q", got, want)
}
@@ -699,7 +699,7 @@
In the next example, `Test` waits for the background goroutine to run and exit
before it returns:
-```
+```go
func TestWaitForGoroutine(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
go func() {
@@ -713,7 +713,7 @@
The bubble's root goroutine returns before that time is reached,
so the `AfterFunc` never runs:
-```
+```go
func TestDoNotWaitForTimer(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
time.AfterFunc(1 * time.Nanosecond, func() {
@@ -729,7 +729,7 @@
because `Test` is waiting for all goroutines in the bubble to finish
but the sleeping goroutine is waiting for time to advance.
-```
+```go
func TestDeadlock(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
go func() {
@@ -912,7 +912,7 @@
The original version of the API created a bubble with a `Run` function:
-```
+```go
// Run executes f in a new bubble.
func Run(f func())
```
diff --git a/_content/blog/toward-go2.md b/_content/blog/toward-go2.md
index 64dc8d7..744beda 100644
--- a/_content/blog/toward-go2.md
+++ b/_content/blog/toward-go2.md
@@ -278,11 +278,13 @@
the subtraction gives a result of ten milliseconds, perhaps plus or
minus a small measurement error.
- start := time.Now() // 3:04:05.000
- event()
- end := time.Now() // 3:04:05.010
+```go
+start := time.Now() // 3:04:05.000
+event()
+end := time.Now() // 3:04:05.010
- elapsed := end.Sub(start) // 10 ms
+elapsed := end.Sub(start) // 10 ms
+```
This obvious procedure can fail during a [leap second](https://en.wikipedia.org/wiki/Leap_second). When our clocks
are not quite in sync with the daily rotation of the Earth, a leap
@@ -296,11 +298,13 @@
move backward, so that our ten-millisecond event might be timed as
taking negative 990 milliseconds.
- start := time.Now() // 11:59:59.995
- event()
- end := time.Now() // 11:59:59.005 (really 11:59:60.005)
+```go
+start := time.Now() // 11:59:59.995
+event()
+end := time.Now() // 11:59:59.005 (really 11:59:60.005)
- elapsed := end.Sub(start) // –990 ms
+elapsed := end.Sub(start) // –990 ms
+```
Because the time-of-day clock is inaccurate for timing events across
clock resets like this, operating systems now provide a second clock,
@@ -485,16 +489,18 @@
More recently, we designed for Go 1.9 a [math/bits package](https://beta.golang.org/doc/go1.9#math-bits) that
contains various bit manipulation functions:
- package bits // import "math/bits"
+```go
+package bits // import "math/bits"
- func LeadingZeros32(x uint32) int
- func Len32(x uint32) int
- func OnesCount32(x uint32) int
- func Reverse32(x uint32) uint32
- func ReverseBytes32(x uint32) uint32
- func RotateLeft32(x uint32, k int) uint32
- func TrailingZeros32(x uint32) int
- ...
+func LeadingZeros32(x uint32) int
+func Len32(x uint32) int
+func OnesCount32(x uint32) int
+func Reverse32(x uint32) uint32
+func ReverseBytes32(x uint32) uint32
+func RotateLeft32(x uint32, k int) uint32
+func TrailingZeros32(x uint32) int
+...
+```
The package has good Go
implementations of each function, but the compilers also substitute
diff --git a/_content/blog/turkey-doodle.md b/_content/blog/turkey-doodle.md
index a5f6b76..334ca46 100644
--- a/_content/blog/turkey-doodle.md
+++ b/_content/blog/turkey-doodle.md
@@ -94,36 +94,38 @@
the location of the corresponding images,
and where they should be drawn on the background image.
- var (
- // dirs maps each layout element to its location on disk.
- dirs = map[string]string{
- "h": "img/heads",
- "b": "img/eyes_beak",
- "i": "img/index_feathers",
- "m": "img/middle_feathers",
- "r": "img/ring_feathers",
- "p": "img/pinky_feathers",
- "f": "img/feet",
- "w": "img/wing",
- }
+```go
+var (
+ // dirs maps each layout element to its location on disk.
+ dirs = map[string]string{
+ "h": "img/heads",
+ "b": "img/eyes_beak",
+ "i": "img/index_feathers",
+ "m": "img/middle_feathers",
+ "r": "img/ring_feathers",
+ "p": "img/pinky_feathers",
+ "f": "img/feet",
+ "w": "img/wing",
+ }
- // urlMap maps each URL character position to
- // its corresponding layout element.
- urlMap = [...]string{"b", "h", "i", "m", "r", "p", "f", "w"}
+ // urlMap maps each URL character position to
+ // its corresponding layout element.
+ urlMap = [...]string{"b", "h", "i", "m", "r", "p", "f", "w"}
- // layoutMap maps each layout element to its position
- // on the background image.
- layoutMap = map[string]image.Rectangle{
- "h": {image.Pt(109, 50), image.Pt(166, 152)},
- "i": {image.Pt(136, 21), image.Pt(180, 131)},
- "m": {image.Pt(159, 7), image.Pt(201, 126)},
- "r": {image.Pt(188, 20), image.Pt(230, 125)},
- "p": {image.Pt(216, 48), image.Pt(258, 134)},
- "f": {image.Pt(155, 176), image.Pt(243, 213)},
- "w": {image.Pt(169, 118), image.Pt(250, 197)},
- "b": {image.Pt(105, 104), image.Pt(145, 148)},
- }
- )
+ // layoutMap maps each layout element to its position
+ // on the background image.
+ layoutMap = map[string]image.Rectangle{
+ "h": {image.Pt(109, 50), image.Pt(166, 152)},
+ "i": {image.Pt(136, 21), image.Pt(180, 131)},
+ "m": {image.Pt(159, 7), image.Pt(201, 126)},
+ "r": {image.Pt(188, 20), image.Pt(230, 125)},
+ "p": {image.Pt(216, 48), image.Pt(258, 134)},
+ "f": {image.Pt(155, 176), image.Pt(243, 213)},
+ "w": {image.Pt(169, 118), image.Pt(250, 197)},
+ "b": {image.Pt(105, 104), image.Pt(145, 148)},
+ }
+)
+```
The geometry of the points above was calculated by measuring the actual
location and size of each layout element within the image.
@@ -132,35 +134,37 @@
so we load all 106 images (13 \* 8 elements + 1 background + 1 default) into
global variables upon receipt of the first request.
- var (
- // elements maps each layout element to its images.
- elements = make(map[string][]*image.RGBA)
+```go
+var (
+ // elements maps each layout element to its images.
+ elements = make(map[string][]*image.RGBA)
- // backgroundImage contains the background image data.
- backgroundImage *image.RGBA
+ // backgroundImage contains the background image data.
+ backgroundImage *image.RGBA
- // defaultImage is the image that is served if an error occurs.
- defaultImage *image.RGBA
+ // defaultImage is the image that is served if an error occurs.
+ defaultImage *image.RGBA
- // loadOnce is used to call the load function only on the first request.
- loadOnce sync.Once
- )
+ // loadOnce is used to call the load function only on the first request.
+ loadOnce sync.Once
+)
- // load reads the various PNG images from disk and stores them in their
- // corresponding global variables.
- func load() {
- defaultImage = loadPNG(defaultImageFile)
- backgroundImage = loadPNG(backgroundImageFile)
- for dirKey, dir := range dirs {
- paths, err := filepath.Glob(dir + "/*.png")
- if err != nil {
- panic(err)
- }
- for _, p := range paths {
- elements[dirKey] = append(elements[dirKey], loadPNG(p))
- }
- }
- }
+// load reads the various PNG images from disk and stores them in their
+// corresponding global variables.
+func load() {
+ defaultImage = loadPNG(defaultImageFile)
+ backgroundImage = loadPNG(backgroundImageFile)
+ for dirKey, dir := range dirs {
+ paths, err := filepath.Glob(dir + "/*.png")
+ if err != nil {
+ panic(err)
+ }
+ for _, p := range paths {
+ elements[dirKey] = append(elements[dirKey], loadPNG(p))
+ }
+ }
+}
+```
Requests are handled in a straightforward sequence:
diff --git a/_content/blog/type-inference.md b/_content/blog/type-inference.md
index 27f7066..b52fc83 100644
--- a/_content/blog/type-inference.md
+++ b/_content/blog/type-inference.md
@@ -24,7 +24,7 @@
The key phrase here is "automatically deduce ... the type of an expression".
Go supported a basic form of type inference from the start:
-```Go
+```go
const x = expr // the type of x is the type of expr
var x = expr
x := expr
@@ -45,13 +45,13 @@
sugar—the ability to leave away the `var` keyword—into one very compact statement.
Consider the following map variable declaration:
-```Go
+```go
var m map[string]int = map[string]int{}
```
vs
-```Go
+```go
m := map[string]int{}
```
@@ -63,7 +63,7 @@
Consider using the following two functions from the new
[slices package](https://pkg.go.dev/slices):
-```Go
+```go
package slices
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool)
func Sort[S ~[]E, E cmp.Ordered](x S)
@@ -71,7 +71,7 @@
Without type inference, calling `BinarySearch` and `Sort` requires explicit type arguments:
-```Go
+```go
type List []int
var list List
slices.Sort[List, int](list)
@@ -81,7 +81,7 @@
We'd rather not repeat `[List, int]` with each such generic function call.
With type inference the code simplifies to:
-```Go
+```go
type List []int
var list List
slices.Sort(list)
@@ -106,7 +106,7 @@
to go into these type variables.
Let's consider a short example:
-```Go
+```go
// From the slices package
// func Sort[S ~[]E, E cmp.Ordered](x S)
@@ -136,7 +136,7 @@
`S1`, `S2`, `E1`, and `E2` from `slices.EqualFunc`, and `E1` and `E2` from the generic function `equal`.
The local function `foo` calls `slices.EqualFunc` with the `equal` function as an argument:
-```Go
+```go
// From the slices package
// func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool
@@ -169,7 +169,7 @@
Let's look again at our earlier example:
-```Go
+```go
// From the slices package
// func Sort[S ~[]E, E cmp.Ordered](x S)
@@ -244,7 +244,7 @@
For instance, the single equation below allows us to infer the type arguments for
two type parameters:
-```Go
+```go
map[K]V ≡ map[int]string // K ➞ int, V ➞ string (n = 2, m = 1)
```
@@ -255,13 +255,13 @@
For each type parameter declaration
-```Go
+```go
func f[…, P constraint, …]…
```
and explicitly provided type argument
-```Go
+```go
f[…, A, …]…
```
@@ -281,7 +281,7 @@
For each function argument `x` passed to a function parameter `p`
-```Go
+```go
f(…, x, …)
```
@@ -301,7 +301,7 @@
Starting with Go 1.21, an uninstantiated or partially instantiated function
(but not a function call) may also be assigned to a function-typed variable, as in:
-```Go
+```go
// From the slices package
// func Sort[S ~[]E, E cmp.Ordered](x S)
@@ -326,7 +326,7 @@
we can extract a type equation from its constraint because the type parameter
must satisfy the constraint. Given the declaration
-```Go
+```go
func f[…, P constraint, …]…
```
@@ -351,13 +351,13 @@
As mentioned earlier, in Go 1.21 type inference also works in these cases.
For instance, the generic function
-```Go
+```go
func myEq[P comparable](x, y P) bool { return x == y }
```
can be assigned to a variable of function type
-```Go
+```go
var strEq func(x, y string) bool = myEq // same as using myEq[string]
```
@@ -367,7 +367,7 @@
Furthermore, a generic function may be used uninstantiated or partially instantiated as
an argument to another, possibly generic function:
-```Go
+```go
// From the slices package
// func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S
@@ -411,7 +411,7 @@
In the code below, the function body of `sortedPrint` calls `slices.Sort` for the sorting part.
`sortedPrint` and `slices.Sort` are generic functions as both declare type parameters.
-```Go
+```go
// From the slices package
// func Sort[S ~[]E, E cmp.Ordered](x S)
@@ -492,7 +492,7 @@
type arguments for them such that `X` and `Y` become identical and thus the equation
becomes true.
-```Go
+```go
X: map[A]struct{i int; s []B}
Y: map[string]struct{i C; s []byte}
```
@@ -500,7 +500,7 @@
Unification proceeds by comparing the structure of `X` and `Y` recursively, starting at the top.
Simply looking at the structure of the two types we have
-```Go
+```go
map[…]… ≡ map[…]…
```
@@ -512,13 +512,13 @@
Corresponding key types must be identical, and from that we can immediately infer that
the type argument for `A` must be `string`:
-```Go
+```go
A ≡ string => A ➞ string
```
Continuing with the map element types, we arrive at
-```Go
+```go
struct{i int; s []B} ≡ struct{i C; s []byte}
```
@@ -527,7 +527,7 @@
The first field pair is `i int` and `i C`.
The names match and because `int` must unify with `C`, thus
-```Go
+```go
int ≡ C => C ➞ int
```
@@ -535,7 +535,7 @@
traversed, or until a conflict appears.
In this example, eventually we end up with
-```Go
+```go
[]B ≡ []byte => B ≡ byte => B ➞ byte
```
@@ -553,7 +553,7 @@
When the type trees are compared recursively, unification still successfully infers the type argument for `A`.
But the value types of the maps are different and unification fails.
-```Go
+```go
X: map[A]struct{i int; s []B}
Y: map[string]bool
```
@@ -561,14 +561,14 @@
Both `X` and `Y` are map types, so unification proceeds recursively as before, starting with the key types.
We arrive at
-```Go
+```go
A ≡ string => A ➞ string
```
also as before.
But when we proceed with the map's value types we have
-```Go
+```go
struct{…} ≡ bool
```
@@ -581,7 +581,7 @@
Here we have again a version of our initial example but now the type parameter `A` appears twice in `X`,
and `C` appears twice in `Y`.
-```Go
+```go
X: map[A]struct{i int; s []A}
Y: map[string]struct{i C; s []C}
```
@@ -589,14 +589,14 @@
The recursive type unification works out fine at first and we have the following pairings of type
parameters and types:
-```Go
+```go
A ≡ string => A ➞ string // map key type
int ≡ C => C ➞ int // first struct field type
```
When we get to the second struct field type we have
-```Go
+```go
[]A ≡ []C => A ≡ C
```
@@ -711,7 +711,7 @@
To see why this is the case, consider the generic function `g` below
which is invoked with a single argument `x` of type `int`:
-```Go
+```go
func g[A any, B []C, C *A](x A) { … }
var x int
@@ -786,7 +786,7 @@
`foo` is called with a variety of untyped constant arguments, including a variable
`x` of type `int`:
-```Go
+```go
func foo[P any](...P) {}
var x int
@@ -821,7 +821,7 @@
With this information in hand, let's consider the function call
-```Go
+```go
foo(1, 2) // P ➞ int (default type for 1 and 2)
```
@@ -832,7 +832,7 @@
for the same type variable, we have different default types.
Before Go 1.21, this was considered a conflict and led to an error:
-```Go
+```go
foo(1, 2.0) // Go 1.20: inference error: default types int, float64 don't match
```
@@ -845,7 +845,7 @@
the default type that appears later in the list of `int`, `rune`, `float64`, `complex` is
selected, matching the rules for [constant expressions](/ref/spec#Constant_expressions):
-```Go
+```go
foo(1, 2.0) // Go 1.21: P ➞ float64 (larger default type of 1 and 2.0; behavior like in 1 + 2.0)
```
@@ -866,7 +866,7 @@
the type inferred for `P` should be the same irrespective of the order in which
we pass the arguments `s` and `t` ([playground](/play/p/sOlWutKnDFc)).
-```Go
+```go
func foo[P any](...P) (x P) {}
type T struct{}
@@ -942,7 +942,7 @@
[gamma function](https://en.wikipedia.org/wiki/Gamma_function),
it is simply a convenient example.
-```Go
+```go
func fact[P ~int | ~float64](n P) P {
if n {{raw "<"}}= 1 {
return 1
@@ -977,7 +977,7 @@
The effect is as if the recursive call was done indirectly through a `helper` function
([playground](/play/p/TLpo-0auWwC)):
-```Go
+```go
func fact[P ~int | ~float64](n P) P {
if n {{raw "<"}}= 1 {
return 1
@@ -1003,7 +1003,7 @@
which is of course what we'd expect, and which we can verify by explicitly instantiating
the recursive call ([playground](/play/p/zkUFvwJ54lC)):
-```Go
+```go
func fact[P ~int | ~float64](n P) P {
if n {{raw "<"}}= 1 {
return 1
@@ -1030,7 +1030,7 @@
Second, and more pertinent, type parameters allow an entirely new kind of recursive
types. Consider the hypothetical type
-```Go
+```go
type T[P T[P]] interface{ … }
```
diff --git a/_content/blog/unique.md b/_content/blog/unique.md
index d72df17..991d8d3 100644
--- a/_content/blog/unique.md
+++ b/_content/blog/unique.md
@@ -25,7 +25,7 @@
Take the code sample below, which deduplicates strings using just a regular
map.
-```
+```go
var internPool map[string]string
// Intern returns a string that is equal to s but that may share storage with
@@ -110,7 +110,7 @@
Below is an abridged version of the actual code from `net/netip` that uses
`unique`.
-```
+```go
// Addr represents an IPv4 or IPv6 address (with or without a scoped
// addressing zone), similar to net.IP or net.IPAddr.
type Addr struct {
diff --git a/_content/blog/using-go-modules.md b/_content/blog/using-go-modules.md
index f953e0c..06406bb 100644
--- a/_content/blog/using-go-modules.md
+++ b/_content/blog/using-go-modules.md
@@ -70,24 +70,28 @@
Create a new, empty directory somewhere outside `$GOPATH/src`,
`cd` into that directory, and then create a new source file, `hello.go`:
- package hello
+```go
+package hello
- func Hello() string {
- return "Hello, world."
- }
+func Hello() string {
+ return "Hello, world."
+}
+```
Let's write a test, too, in `hello_test.go`:
- package hello
+```go
+package hello
- import "testing"
+import "testing"
- func TestHello(t *testing.T) {
- want := "Hello, world."
- if got := Hello(); got != want {
- t.Errorf("Hello() = %q, want %q", got, want)
- }
+func TestHello(t *testing.T) {
+ want := "Hello, world."
+ if got := Hello(); got != want {
+ t.Errorf("Hello() = %q, want %q", got, want)
}
+}
+```
At this point, the directory contains a package, but not a module,
because there is no `go.mod` file.
@@ -144,13 +148,15 @@
Let's update our `hello.go` to import `rsc.io/quote`
and use it to implement `Hello`:
- package hello
+```go
+package hello
- import "rsc.io/quote"
+import "rsc.io/quote"
- func Hello() string {
- return quote.Hello()
- }
+func Hello() string {
+ return quote.Hello()
+}
+```
Now let’s run the test again:
@@ -348,29 +354,33 @@
the module `rsc.io/quote/v3`.
First we update `hello.go` to add the new function:
- package hello
+```go
+package hello
- import (
- "rsc.io/quote"
- quoteV3 "rsc.io/quote/v3"
- )
+import (
+ "rsc.io/quote"
+ quoteV3 "rsc.io/quote/v3"
+)
- func Hello() string {
- return quote.Hello()
- }
+func Hello() string {
+ return quote.Hello()
+}
- func Proverb() string {
- return quoteV3.Concurrency()
- }
+func Proverb() string {
+ return quoteV3.Concurrency()
+}
+```
Then we add a test to `hello_test.go`:
- func TestProverb(t *testing.T) {
- want := "Concurrency is not parallelism."
- if got := Proverb(); got != want {
- t.Errorf("Proverb() = %q, want %q", got, want)
- }
+```go
+func TestProverb(t *testing.T) {
+ want := "Concurrency is not parallelism."
+ if got := Proverb(); got != want {
+ t.Errorf("Proverb() = %q, want %q", got, want)
}
+}
+```
Then we can test our code:
@@ -441,32 +451,36 @@
We can update our use of `quote.Hello()` in `hello.go` to use `quoteV3.HelloV3()`:
- package hello
+```go
+package hello
- import quoteV3 "rsc.io/quote/v3"
+import quoteV3 "rsc.io/quote/v3"
- func Hello() string {
- return quoteV3.HelloV3()
- }
+func Hello() string {
+ return quoteV3.HelloV3()
+}
- func Proverb() string {
- return quoteV3.Concurrency()
- }
+func Proverb() string {
+ return quoteV3.Concurrency()
+}
+```
And then at this point, there's no need for the renamed import anymore,
so we can undo that:
- package hello
+```go
+package hello
- import "rsc.io/quote/v3"
+import "rsc.io/quote/v3"
- func Hello() string {
- return quote.HelloV3()
- }
+func Hello() string {
+ return quote.HelloV3()
+}
- func Proverb() string {
- return quote.Concurrency()
- }
+func Proverb() string {
+ return quote.Concurrency()
+}
+```
Let's re-run the tests to make sure everything is working:
diff --git a/_content/blog/wasmexport.md b/_content/blog/wasmexport.md
index 6965357..e11e5c9 100644
--- a/_content/blog/wasmexport.md
+++ b/_content/blog/wasmexport.md
@@ -41,7 +41,7 @@
To use the `go:wasmexport` directive, simply add it to a function definition:
-```
+```go
//go:wasmexport add
func add(a, b int32) int32 { return a + b }
```
@@ -80,7 +80,7 @@
Here is an example using [Wazero](https://wazero.io/), a Go-based Wasm runtime
implementation:
-```
+```go
// Create a Wasm runtime, set up WASI.
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
diff --git a/_content/blog/when-generics.md b/_content/blog/when-generics.md
index ff799e2..8e07c0b 100644
--- a/_content/blog/when-generics.md
+++ b/_content/blog/when-generics.md
@@ -62,15 +62,17 @@
in a map of any type:
{{raw `
- // MapKeys returns a slice of all the keys in m.
- // The keys are not returned in any particular order.
- func MapKeys[Key comparable, Val any](m map[Key]Val) []Key {
- s := make([]Key, 0, len(m))
- for k := range m {
- s = append(s, k)
- }
- return s
+~~~go
+// MapKeys returns a slice of all the keys in m.
+// The keys are not returned in any particular order.
+func MapKeys[Key comparable, Val any](m map[Key]Val) []Key {
+ s := make([]Key, 0, len(m))
+ for k := range m {
+ s = append(s, k)
}
+ return s
+}
+~~~
`}}
This code doesn't assume anything about the map key type, and it
@@ -106,46 +108,48 @@
look like using type parameters:
{{raw `
- // Tree is a binary tree.
- type Tree[T any] struct {
- cmp func(T, T) int
- root *node[T]
- }
+~~~go
+// Tree is a binary tree.
+type Tree[T any] struct {
+ cmp func(T, T) int
+ root *node[T]
+}
- // A node in a Tree.
- type node[T any] struct {
- left, right *node[T]
- val T
- }
+// A node in a Tree.
+type node[T any] struct {
+ left, right *node[T]
+ val T
+}
- // find returns a pointer to the node containing val,
- // or, if val is not present, a pointer to where it
- // would be placed if added.
- func (bt *Tree[T]) find(val T) **node[T] {
- pl := &bt.root
- for *pl != nil {
- switch cmp := bt.cmp(val, (*pl).val); {
- case cmp < 0:
- pl = &(*pl).left
- case cmp > 0:
- pl = &(*pl).right
- default:
- return pl
- }
+// find returns a pointer to the node containing val,
+// or, if val is not present, a pointer to where it
+// would be placed if added.
+func (bt *Tree[T]) find(val T) **node[T] {
+ pl := &bt.root
+ for *pl != nil {
+ switch cmp := bt.cmp(val, (*pl).val); {
+ case cmp < 0:
+ pl = &(*pl).left
+ case cmp > 0:
+ pl = &(*pl).right
+ default:
+ return pl
}
- return pl
}
+ return pl
+}
- // Insert inserts val into bt if not already there,
- // and reports whether it was inserted.
- func (bt *Tree[T]) Insert(val T) bool {
- pl := bt.find(val)
- if *pl != nil {
- return false
- }
- *pl = &node[T]{val: val}
- return true
+// Insert inserts val into bt if not already there,
+// and reports whether it was inserted.
+func (bt *Tree[T]) Insert(val T) bool {
+ pl := bt.find(val)
+ if *pl != nil {
+ return false
}
+ *pl = &node[T]{val: val}
+ return true
+}
+~~~
`}}
Each node in the tree contains a value of the type parameter `T`.
@@ -207,21 +211,23 @@
`sort.Interface` for any slice type:
{{raw `
- // SliceFn implements sort.Interface for a slice of T.
- type SliceFn[T any] struct {
- s []T
- less func(T, T) bool
- }
+~~~go
+// SliceFn implements sort.Interface for a slice of T.
+type SliceFn[T any] struct {
+ s []T
+ less func(T, T) bool
+}
- func (s SliceFn[T]) Len() int {
- return len(s.s)
- }
- func (s SliceFn[T]) Swap(i, j int) {
- s.s[i], s.s[j] = s.s[j], s.s[i]
- }
- func (s SliceFn[T]) Less(i, j int) bool {
- return s.less(s.s[i], s.s[j])
- }
+func (s SliceFn[T]) Len() int {
+ return len(s.s)
+}
+func (s SliceFn[T]) Swap(i, j int) {
+ s.s[i], s.s[j] = s.s[j], s.s[i]
+}
+func (s SliceFn[T]) Less(i, j int) bool {
+ return s.less(s.s[i], s.s[j])
+}
+~~~
`}}
For any slice type, the `Len` and `Swap` methods are exactly the same.
@@ -234,10 +240,12 @@
function:
{{raw `
- // SortFn sorts s in place using a comparison function.
- func SortFn[T any](s []T, less func(T, T) bool) {
- sort.Sort(SliceFn[T]{s, less})
- }
+~~~go
+// SortFn sorts s in place using a comparison function.
+func SortFn[T any](s []T, less func(T, T) bool) {
+ sort.Sort(SliceFn[T]{s, less})
+}
+~~~
`}}
This is similar to the standard library function `sort.Slice`, but the
@@ -281,9 +289,11 @@
version, which uses a type parameter.
{{raw `
- func ReadSome(r io.Reader) ([]byte, error)
+~~~go
+func ReadSome(r io.Reader) ([]byte, error)
- func ReadSome[T io.Reader](r T) ([]byte, error)
+func ReadSome[T io.Reader](r T) ([]byte, error)
+~~~
`}}
Don't make that kind of change.
diff --git a/_content/blog/why-generics.md b/_content/blog/why-generics.md
index bce3a0f..1849ac7 100644
--- a/_content/blog/why-generics.md
+++ b/_content/blog/why-generics.md
@@ -50,15 +50,17 @@
Let's say it's a slice of int.
{{raw `
- func ReverseInts(s []int) {
- first := 0
- last := len(s)
- for first < last {
- s[first], s[last] = s[last], s[first]
- first++
- last--
- }
+~~~go
+func ReverseInts(s []int) {
+ first := 0
+ last := len(s)
+ for first < last {
+ s[first], s[last] = s[last], s[first]
+ first++
+ last--
}
+}
+~~~
`}}
Pretty simple, but even for a simple function like that you'd want to
@@ -67,15 +69,17 @@
I'm sure many readers have spotted it already.
{{raw `
- func ReverseInts(s []int) {
- first := 0
- last := len(s) - 1
- for first < last {
- s[first], s[last] = s[last], s[first]
- first++
- last--
- }
+~~~go
+func ReverseInts(s []int) {
+ first := 0
+ last := len(s) - 1
+ for first < last {
+ s[first], s[last] = s[last], s[first]
+ first++
+ last--
}
+}
+~~~
`}}
We need to subtract 1 when we set the variable last.
@@ -83,15 +87,17 @@
Now let's reverse a slice of string.
{{raw `
- func ReverseStrings(s []string) {
- first := 0
- last := len(s) - 1
- for first < last {
- s[first], s[last] = s[last], s[first]
- first++
- last--
- }
+~~~go
+func ReverseStrings(s []string) {
+ first := 0
+ last := len(s) - 1
+ for first < last {
+ s[first], s[last] = s[last], s[first]
+ first++
+ last--
}
+}
+~~~
`}}
If you compare `ReverseInts` and `ReverseStrings`, you'll see that the
@@ -372,15 +378,17 @@
Here is the generic Reverse function in this design.
{{raw `
- func Reverse (type Element) (s []Element) {
- first := 0
- last := len(s) - 1
- for first < last {
- s[first], s[last] = s[last], s[first]
- first++
- last--
- }
+~~~go
+func Reverse (type Element) (s []Element) {
+ first := 0
+ last := len(s) - 1
+ for first < last {
+ s[first], s[last] = s[last], s[first]
+ first++
+ last--
}
+}
+~~~
`}}
You'll notice that the body of the function is exactly the same.
@@ -396,10 +404,12 @@
a type argument, which is like any other argument except that it's a
type.
- func ReverseAndPrint(s []int) {
- Reverse(int)(s)
- fmt.Println(s)
- }
+```go
+func ReverseAndPrint(s []int) {
+ Reverse(int)(s)
+ fmt.Println(s)
+}
+```
That is the `(int)` seen after `Reverse` in this example.
@@ -409,10 +419,12 @@
Calling a generic function just looks like calling any other function.
- func ReverseAndPrint(s []int) {
- Reverse(s)
- fmt.Println(s)
- }
+```go
+func ReverseAndPrint(s []int) {
+ Reverse(s)
+ fmt.Println(s)
+}
+```
In other words, although the generic `Reverse` function is slightly
more complex than `ReverseInts` and `ReverseStrings`, that complexity
@@ -436,14 +448,16 @@
Let's take a quick look at a different function.
{{raw `
- func IndexByte (type T Sequence) (s T, b byte) int {
- for i := 0; i < len(s); i++ {
- if s[i] == b {
- return i
- }
+~~~go
+func IndexByte (type T Sequence) (s T, b byte) int {
+ for i := 0; i < len(s); i++ {
+ if s[i] == b {
+ return i
}
- return -1
}
+ return -1
+}
+~~~
`}}
Currently both the bytes package and the strings package in the
@@ -470,9 +484,11 @@
This is how the Sequence contract is defined for this example.
- contract Sequence(T) {
- T string, []byte
- }
+```go
+contract Sequence(T) {
+ T string, []byte
+}
+```
It's pretty simple, since this is a simple example: the type parameter
`T` can be either `string` or `[]byte`.
@@ -497,13 +513,15 @@
method to return a `[]string` of the string representation of all the
elements in `s`.
- func ToStrings (type E Stringer) (s []E) []string {
- r := make([]string, len(s))
- for i, v := range s {
- r[i] = v.String()
- }
- return r
+```go
+func ToStrings (type E Stringer) (s []E) []string {
+ r := make([]string, len(s))
+ for i, v := range s {
+ r[i] = v.String()
}
+ return r
+}
+```
It's pretty straightforward: walk through the slice, call the `String`
method on each element, and return a slice of the resulting strings.
@@ -512,9 +530,11 @@
method.
The Stringer contract ensures that.
- contract Stringer(T) {
- T String() string
- }
+```go
+contract Stringer(T) {
+ T String() string
+}
+```
The contract simply says that `T` has to implement the `String`
method.
@@ -533,20 +553,22 @@
Here is an example of a contract with multiple type parameters.
- type Graph (type Node, Edge G) struct { ... }
+```go
+type Graph (type Node, Edge G) struct { ... }
- contract G(Node, Edge) {
- Node Edges() []Edge
- Edge Nodes() (from Node, to Node)
- }
+contract G(Node, Edge) {
+ Node Edges() []Edge
+ Edge Nodes() (from Node, to Node)
+}
- func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) {
- ...
- }
+func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) {
+ ...
+}
- func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge {
- ...
- }
+func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge {
+ ...
+}
+```
Here we're describing a graph, built from nodes and edges.
We're not requiring a particular data structure for the graph.
@@ -576,24 +598,28 @@
This is what it looks like with our design.
{{raw `
- func Min (type T Ordered) (a, b T) T {
- if a < b {
- return a
- }
- return b
+~~~go
+func Min (type T Ordered) (a, b T) T {
+ if a < b {
+ return a
}
+ return b
+}
+~~~
`}}
The `Ordered` contract says that the type T has to be an ordered type,
which means that it supports operators like less than, greater than,
and so forth.
- contract Ordered(T) {
- T int, int8, int16, int32, int64,
- uint, uint8, uint16, uint32, uint64, uintptr,
- float32, float64,
- string
- }
+```go
+contract Ordered(T) {
+ T int, int8, int16, int32, int64,
+ uint, uint8, uint16, uint32, uint64, uintptr,
+ float32, float64,
+ string
+}
+```
The `Ordered` contract is just a list of all the ordered types that
are defined by the language.
@@ -621,12 +647,14 @@
contracts package.
{{raw `
- func Min (type T contracts.Ordered) (a, b T) T {
- if a < b {
- return a
- }
- return b
+~~~go
+func Min (type T contracts.Ordered) (a, b T) T {
+ if a < b {
+ return a
}
+ return b
+}
+~~~
`}}
### Generic data structures
@@ -635,41 +663,47 @@
tree. In this example the tree has a comparison function, so there
are no requirements on the element type.
- type Tree (type E) struct {
- root *node(E)
- compare func(E, E) int
- }
+```go
+type Tree (type E) struct {
+ root *node(E)
+ compare func(E, E) int
+}
- type node (type E) struct {
- val E
- left, right *node(E)
- }
+type node (type E) struct {
+ val E
+ left, right *node(E)
+}
+```
Here is how to create a new binary tree.
The comparison function is passed to the `New` function.
- func New (type E) (cmp func(E, E) int) *Tree(E) {
- return &Tree(E){compare: cmp}
- }
+```go
+func New (type E) (cmp func(E, E) int) *Tree(E) {
+ return &Tree(E){compare: cmp}
+}
+```
An unexported method returns a pointer either to the slot holding v,
or to the location in the tree where it should go.
{{raw `
- func (t *Tree(E)) find(v E) **node(E) {
- pn := &t.root
- for *pn != nil {
- switch cmp := t.compare(v, (*pn).val); {
- case cmp < 0:
- pn = &(*pn).left
- case cmp > 0:
- pn = &(*pn).right
- default:
- return pn
- }
+~~~go
+func (t *Tree(E)) find(v E) **node(E) {
+ pn := &t.root
+ for *pn != nil {
+ switch cmp := t.compare(v, (*pn).val); {
+ case cmp < 0:
+ pn = &(*pn).left
+ case cmp > 0:
+ pn = &(*pn).right
+ default:
+ return pn
}
- return pn
}
+ return pn
+}
+~~~
`}}
The details here don't really matter, especially since I haven't
@@ -679,20 +713,24 @@
This is the code for testing whether the tree contains a value.
- func (t *Tree(E)) Contains(v E) bool {
- return *t.find(e) != nil
- }
+```go
+func (t *Tree(E)) Contains(v E) bool {
+ return *t.find(e) != nil
+}
+```
This is the code for inserting a new value.
- func (t *Tree(E)) Insert(v E) bool {
- pn := t.find(v)
- if *pn != nil {
- return false
- }
- *pn = &node(E){val: v}
- return true
+```go
+func (t *Tree(E)) Insert(v E) bool {
+ pn := t.find(v)
+ if *pn != nil {
+ return false
}
+ *pn = &node(E){val: v}
+ return true
+}
+```
Notice that the type `node` has a type argument `E`.
This is what it looks like to write a generic data structure.
@@ -701,14 +739,16 @@
Using the tree is pretty simple.
- var intTree = tree.New(func(a, b int) int { return a - b })
+```go
+var intTree = tree.New(func(a, b int) int { return a - b })
- func InsertAndCheck(v int) {
- intTree.Insert(v)
- if !intTree.Contains(v) {
- log.Fatalf("%d not found after insertion", v)
- }
+func InsertAndCheck(v int) {
+ intTree.Insert(v)
+ if !intTree.Contains(v) {
+ log.Fatalf("%d not found after insertion", v)
}
+}
+```
That's as it should be.
It's a bit harder to write a generic data structure, because you often
diff --git a/_content/blog/wire.md b/_content/blog/wire.md
index 9fe28c4..b2210db 100644
--- a/_content/blog/wire.md
+++ b/_content/blog/wire.md
@@ -21,8 +21,10 @@
by explicitly providing components with all of the dependencies they need to work.
In Go, this often takes the form of passing dependencies to constructors:
- // NewUserStore returns a UserStore that uses cfg and db as dependencies.
- func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
+```go
+// NewUserStore returns a UserStore that uses cfg and db as dependencies.
+func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
+```
This technique works great at small scale,
but larger applications can have a complex graph of dependencies,
@@ -104,33 +106,39 @@
which are described simply as parameters to the function.
Here's some sample code that defines three providers:
- // NewUserStore is the same function we saw above; it is a provider for UserStore,
- // with dependencies on *Config and *mysql.DB.
- func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
+```go
+// NewUserStore is the same function we saw above; it is a provider for UserStore,
+// with dependencies on *Config and *mysql.DB.
+func NewUserStore(cfg *Config, db *mysql.DB) (*UserStore, error) {...}
- // NewDefaultConfig is a provider for *Config, with no dependencies.
- func NewDefaultConfig() *Config {...}
+// NewDefaultConfig is a provider for *Config, with no dependencies.
+func NewDefaultConfig() *Config {...}
- // NewDB is a provider for *mysql.DB based on some connection info.
- func NewDB(info *ConnectionInfo) (*mysql.DB, error) {...}
+// NewDB is a provider for *mysql.DB based on some connection info.
+func NewDB(info *ConnectionInfo) (*mysql.DB, error) {...}
+```
Providers that are commonly used together can be grouped into `ProviderSets`.
For example, it's common to use a default `*Config` when creating a `*UserStore`,
so we can group `NewUserStore` and `NewDefaultConfig` in a `ProviderSet`:
- var UserStoreSet = wire.ProviderSet(NewUserStore, NewDefaultConfig)
+```go
+var UserStoreSet = wire.ProviderSet(NewUserStore, NewDefaultConfig)
+```
_Injectors_ are generated functions that call providers in dependency order.
You write the injector's signature, including any needed inputs as arguments,
and insert a call to `wire.Build` with the list of providers or provider
sets that are needed to construct the end result:
- func initUserStore() (*UserStore, error) {
- // We're going to get an error, because NewDB requires a *ConnectionInfo
- // and we didn't provide one.
- wire.Build(UserStoreSet, NewDB)
- return nil, nil // These return values are ignored.
- }
+```go
+func initUserStore() (*UserStore, error) {
+ // We're going to get an error, because NewDB requires a *ConnectionInfo
+ // and we didn't provide one.
+ wire.Build(UserStoreSet, NewDB)
+ return nil, nil // These return values are ignored.
+}
+```
Now we run go generate to execute wire:
@@ -143,30 +151,34 @@
We can either add a provider for it to `wire.Build`,
or add it as an argument:
- func initUserStore(info ConnectionInfo) (*UserStore, error) {
- wire.Build(UserStoreSet, NewDB)
- return nil, nil // These return values are ignored.
- }
+```go
+func initUserStore(info ConnectionInfo) (*UserStore, error) {
+ wire.Build(UserStoreSet, NewDB)
+ return nil, nil // These return values are ignored.
+}
+```
Now `go generate` will create a new file with the generated code:
- // File: wire_gen.go
- // Code generated by Wire. DO NOT EDIT.
- //go:generate wire
- //+build !wireinject
+```go
+// File: wire_gen.go
+// Code generated by Wire. DO NOT EDIT.
+//go:generate wire
+//+build !wireinject
- func initUserStore(info ConnectionInfo) (*UserStore, error) {
- defaultConfig := NewDefaultConfig()
- db, err := NewDB(info)
- if err != nil {
- return nil, err
- }
- userStore, err := NewUserStore(defaultConfig, db)
- if err != nil {
- return nil, err
- }
- return userStore, nil
+func initUserStore(info ConnectionInfo) (*UserStore, error) {
+ defaultConfig := NewDefaultConfig()
+ db, err := NewDB(info)
+ if err != nil {
+ return nil, err
}
+ userStore, err := NewUserStore(defaultConfig, db)
+ if err != nil {
+ return nil, err
+ }
+ return userStore, nil
+}
+```
Any non-injector declarations are copied into the generated file.
There is no dependency on Wire at runtime: