exec
+// exec
// function.
package main
@@ -28,7 +28,7 @@ func main() {
}
// `Exec` requires arguments in slice form (as
- // apposed to one big string). We'll give `ls` a few
+ // opposed to one big string). We'll give `ls` a few
// common arguments. Note that the first argument should
// be the program name.
args := []string{"ls", "-a", "-l", "-h"}
diff --git a/examples/execing-processes/execing-processes.hash b/examples/execing-processes/execing-processes.hash
index 90da7c400..90bd32578 100644
--- a/examples/execing-processes/execing-processes.hash
+++ b/examples/execing-processes/execing-processes.hash
@@ -1,2 +1,2 @@
-7a8185c4b55c20a678f1e51698f0f4b6e25d4536
-T3da5euHejy
+568ae983493addff02d2ce8df57f41daf537f077
+s9qg7olf1dM
diff --git a/examples/for/for.go b/examples/for/for.go
index 9a4df3055..83ca1bf71 100644
--- a/examples/for/for.go
+++ b/examples/for/for.go
@@ -15,10 +15,16 @@ func main() {
}
// A classic initial/condition/after `for` loop.
- for j := 7; j <= 9; j++ {
+ for j := 0; j < 3; j++ {
fmt.Println(j)
}
+ // Another way of accomplishing the basic "do this
+ // N times" iteration is `range` over an integer.
+ for i := range 3 {
+ fmt.Println("range", i)
+ }
+
// `for` without a condition will loop repeatedly
// until you `break` out of the loop or `return` from
// the enclosing function.
@@ -29,7 +35,7 @@ func main() {
// You can also `continue` to the next iteration of
// the loop.
- for n := 0; n <= 5; n++ {
+ for n := range 6 {
if n%2 == 0 {
continue
}
diff --git a/examples/for/for.hash b/examples/for/for.hash
index 9473e965f..0beaf5928 100644
--- a/examples/for/for.hash
+++ b/examples/for/for.hash
@@ -1,2 +1,2 @@
-7af221b7da2f2b22b0b1b0a1b365afc5a56ef815
-2-4H-ArwHHS
+8eeb5be15c3c5fc3f9d0d8009dfcec771dc5e03d
+_F2rYHNilKa
diff --git a/examples/for/for.sh b/examples/for/for.sh
index 12785ebb4..b7bc0767b 100644
--- a/examples/for/for.sh
+++ b/examples/for/for.sh
@@ -2,9 +2,12 @@ $ go run for.go
1
2
3
-7
-8
-9
+0
+1
+2
+range 0
+range 1
+range 2
loop
1
3
diff --git a/examples/generics/generics.go b/examples/generics/generics.go
new file mode 100644
index 000000000..470594293
--- /dev/null
+++ b/examples/generics/generics.go
@@ -0,0 +1,79 @@
+// Starting with version 1.18, Go has added support for
+// _generics_, also known as _type parameters_.
+
+package main
+
+import "fmt"
+
+// As an example of a generic function, `SlicesIndex` takes
+// a slice of any `comparable` type and an element of that
+// type and returns the index of the first occurrence of
+// v in s, or -1 if not present. The `comparable` constraint
+// means that we can compare values of this type with the
+// `==` and `!=` operators. For a more thorough explanation
+// of this type signature, see [this blog post](https://go.dev/blog/deconstructing-type-parameters).
+// Note that this function exists in the standard library
+// as [slices.Index](https://pkg.go.dev/slices#Index).
+func SlicesIndex[S ~[]E, E comparable](s S, v E) int {
+ for i := range s {
+ if v == s[i] {
+ return i
+ }
+ }
+ return -1
+}
+
+// As an example of a generic type, `List` is a
+// singly-linked list with values of any type.
+type List[T any] struct {
+ head, tail *element[T]
+}
+
+type element[T any] struct {
+ next *element[T]
+ val T
+}
+
+// We can define methods on generic types just like we
+// do on regular types, but we have to keep the type
+// parameters in place. The type is `List[T]`, not `List`.
+func (lst *List[T]) Push(v T) {
+ if lst.tail == nil {
+ lst.head = &element[T]{val: v}
+ lst.tail = lst.head
+ } else {
+ lst.tail.next = &element[T]{val: v}
+ lst.tail = lst.tail.next
+ }
+}
+
+// AllElements returns all the List elements as a slice.
+// In the next example we'll see a more idiomatic way
+// of iterating over all elements of custom types.
+func (lst *List[T]) AllElements() []T {
+ var elems []T
+ for e := lst.head; e != nil; e = e.next {
+ elems = append(elems, e.val)
+ }
+ return elems
+}
+
+func main() {
+ var s = []string{"foo", "bar", "zoo"}
+
+ // When invoking generic functions, we can often rely
+ // on _type inference_. Note that we don't have to
+ // specify the types for `S` and `E` when
+ // calling `SlicesIndex` - the compiler infers them
+ // automatically.
+ fmt.Println("index of zoo:", SlicesIndex(s, "zoo"))
+
+ // ... though we could also specify them explicitly.
+ _ = SlicesIndex[[]string, string](s, "zoo")
+
+ lst := List[int]{}
+ lst.Push(10)
+ lst.Push(13)
+ lst.Push(23)
+ fmt.Println("list:", lst.AllElements())
+}
diff --git a/examples/generics/generics.hash b/examples/generics/generics.hash
new file mode 100644
index 000000000..ef92af1b8
--- /dev/null
+++ b/examples/generics/generics.hash
@@ -0,0 +1,2 @@
+1ad71763360077271687c5e9d147c89c0b580b0a
+7v7vElzhAeO
diff --git a/examples/generics/generics.sh b/examples/generics/generics.sh
new file mode 100644
index 000000000..90b52a3d5
--- /dev/null
+++ b/examples/generics/generics.sh
@@ -0,0 +1,3 @@
+$ go run generics.go
+index of zoo: 2
+list: [10 13 23]
diff --git a/examples/goroutines/goroutines.go b/examples/goroutines/goroutines.go
index 4943ec93f..2b9e26c1e 100644
--- a/examples/goroutines/goroutines.go
+++ b/examples/goroutines/goroutines.go
@@ -8,7 +8,7 @@ import (
)
func f(from string) {
- for i := 0; i < 3; i++ {
+ for i := range 3 {
fmt.Println(from, ":", i)
}
}
diff --git a/examples/goroutines/goroutines.hash b/examples/goroutines/goroutines.hash
index 63a8b2c4a..7ea80e0b6 100644
--- a/examples/goroutines/goroutines.hash
+++ b/examples/goroutines/goroutines.hash
@@ -1,2 +1,2 @@
-08aa2b9e426724e07ec83162eb6892648ccc7fd5
-I7scqRijEJt
+b7455068d7f944d7c1a2764e5ec05bee53296e62
+0fx_WokYVFO
diff --git a/examples/goroutines/goroutines.sh b/examples/goroutines/goroutines.sh
index 1d42ee279..38506edba 100644
--- a/examples/goroutines/goroutines.sh
+++ b/examples/goroutines/goroutines.sh
@@ -1,7 +1,8 @@
# When we run this program, we see the output of the
-# blocking call first, then the interleaved output of the
-# two goroutines. This interleaving reflects the
-# goroutines being run concurrently by the Go runtime.
+# blocking call first, then the output of the two
+# goroutines. The goroutines' output may be interleaved,
+# because goroutines are being run concurrently by the
+# Go runtime.
$ go run goroutines.go
direct : 0
direct : 1
diff --git a/examples/http-clients/http-clients.go b/examples/http-client/http-client.go
similarity index 94%
rename from examples/http-clients/http-clients.go
rename to examples/http-client/http-client.go
index 7cd71ef73..57b22f24c 100644
--- a/examples/http-clients/http-clients.go
+++ b/examples/http-client/http-client.go
@@ -17,7 +17,7 @@ func main() {
// object and calling its `Get` method; it uses the
// `http.DefaultClient` object which has useful default
// settings.
- resp, err := http.Get("http://gobyexample.com")
+ resp, err := http.Get("https://gobyexample.com")
if err != nil {
panic(err)
}
diff --git a/examples/http-client/http-client.hash b/examples/http-client/http-client.hash
new file mode 100644
index 000000000..81933641e
--- /dev/null
+++ b/examples/http-client/http-client.hash
@@ -0,0 +1,2 @@
+1497e193431e4740f593039f613773daaf97772e
+vFW_el7oHMk
diff --git a/examples/http-clients/http-clients.sh b/examples/http-client/http-client.sh
similarity index 100%
rename from examples/http-clients/http-clients.sh
rename to examples/http-client/http-client.sh
diff --git a/examples/http-clients/http-clients.hash b/examples/http-clients/http-clients.hash
deleted file mode 100644
index b36a4b2da..000000000
--- a/examples/http-clients/http-clients.hash
+++ /dev/null
@@ -1,2 +0,0 @@
-fbc80f8cfcd34e9daa3c52c23f6720f6ef7019dc
-kHCcVLoz7nd
diff --git a/examples/http-servers/http-servers.go b/examples/http-server/http-server.go
similarity index 100%
rename from examples/http-servers/http-servers.go
rename to examples/http-server/http-server.go
diff --git a/examples/http-servers/http-servers.hash b/examples/http-server/http-server.hash
similarity index 100%
rename from examples/http-servers/http-servers.hash
rename to examples/http-server/http-server.hash
diff --git a/examples/http-servers/http-servers.sh b/examples/http-server/http-server.sh
similarity index 78%
rename from examples/http-servers/http-servers.sh
rename to examples/http-server/http-server.sh
index 2db5f4542..5a5e3558b 100644
--- a/examples/http-servers/http-servers.sh
+++ b/examples/http-server/http-server.sh
@@ -1,5 +1,5 @@
# Run the server in the background.
-$ go run http-servers.go &
+$ go run http-server.go &
# Access the `/hello` route.
$ curl localhost:8090/hello
diff --git a/examples/if-else/if-else.go b/examples/if-else/if-else.go
index 1f2a4038f..a2a2f14e6 100644
--- a/examples/if-else/if-else.go
+++ b/examples/if-else/if-else.go
@@ -19,9 +19,15 @@ func main() {
fmt.Println("8 is divisible by 4")
}
+ // Logical operators like `&&` and `||` are often
+ // useful in conditions.
+ if 8%2 == 0 || 7%2 == 0 {
+ fmt.Println("either 8 or 7 are even")
+ }
+
// A statement can precede conditionals; any variables
- // declared in this statement are available in all
- // branches.
+ // declared in this statement are available in the current
+ // and all subsequent branches.
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
diff --git a/examples/if-else/if-else.hash b/examples/if-else/if-else.hash
index 8f1ebb5de..4de271b79 100644
--- a/examples/if-else/if-else.hash
+++ b/examples/if-else/if-else.hash
@@ -1,2 +1,2 @@
-ae7f289ac1b2b1f152cd1952b93769209eed8e1d
-QlMkcwHvmns
+fd9e491f9891e6a9593c2c1d640c1df113ce3ccf
+RKgKzCe7qcF
diff --git a/examples/if-else/if-else.sh b/examples/if-else/if-else.sh
index 13c363f30..502ca1e03 100644
--- a/examples/if-else/if-else.sh
+++ b/examples/if-else/if-else.sh
@@ -1,8 +1,9 @@
-$ go run if-else.go
+$ go run if-else.go
7 is odd
8 is divisible by 4
+either 8 or 7 are even
9 has 1 digit
-# There is no [ternary if](http://en.wikipedia.org/wiki/%3F:)
+# There is no [ternary if](https://en.wikipedia.org/wiki/%3F:)
# in Go, so you'll need to use a full `if` statement even
# for basic conditions.
diff --git a/examples/interfaces/interfaces.go b/examples/interfaces/interfaces.go
index 806ffa7d4..b6844f376 100644
--- a/examples/interfaces/interfaces.go
+++ b/examples/interfaces/interfaces.go
@@ -51,6 +51,15 @@ func measure(g geometry) {
fmt.Println(g.perim())
}
+// Sometimes it's useful to know the runtime type of an
+// interface value. One option is using a *type assertion*
+// as shown here; another is a [type `switch`](switch).
+func detectCircle(g geometry) {
+ if c, ok := g.(circle); ok {
+ fmt.Println("circle with radius", c.radius)
+ }
+}
+
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
@@ -61,4 +70,7 @@ func main() {
// these structs as arguments to `measure`.
measure(r)
measure(c)
+
+ detectCircle(r)
+ detectCircle(c)
}
diff --git a/examples/interfaces/interfaces.hash b/examples/interfaces/interfaces.hash
index b228f689a..4d07d2c3f 100644
--- a/examples/interfaces/interfaces.hash
+++ b/examples/interfaces/interfaces.hash
@@ -1,2 +1,2 @@
-d4ea9541521cfee94107ba9331d0dabb1f9f16c1
-XJASG4MxBQr
+6324a4bdb756a0ec2ccc60e13c97d2650e730ed6
+xAAbgd7GOKD
diff --git a/examples/interfaces/interfaces.sh b/examples/interfaces/interfaces.sh
index f800e3a30..a67a8b14c 100644
--- a/examples/interfaces/interfaces.sh
+++ b/examples/interfaces/interfaces.sh
@@ -5,6 +5,7 @@ $ go run interfaces.go
{5}
78.53981633974483
31.41592653589793
+circle with radius 5
-# To learn more about Go's interfaces, check out this
-# [great blog post](http://jordanorelli.tumblr.com/post/32665860244/how-to-use-interfaces-in-go).
+# To understand how Go's interfaces work under the hood,
+# check out this [blog post](https://research.swtch.com/interfaces).
diff --git a/examples/json/json.go b/examples/json/json.go
index 259478632..0443d7213 100644
--- a/examples/json/json.go
+++ b/examples/json/json.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"os"
+ "strings"
)
// We'll use these two structs to demonstrate encoding and
@@ -121,4 +122,11 @@ func main() {
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
+
+ // Streaming reads from `os.Reader`s like `os.Stdin`
+ // or HTTP request bodies is done with `json.Decoder`.
+ dec := json.NewDecoder(strings.NewReader(str))
+ res1 := response2{}
+ dec.Decode(&res1)
+ fmt.Println(res1)
}
diff --git a/examples/json/json.hash b/examples/json/json.hash
index 60f6c01bd..57a0e2aa6 100644
--- a/examples/json/json.hash
+++ b/examples/json/json.hash
@@ -1,2 +1,2 @@
-35295476f817fe575619b6168273a29eddd7f545
-JOQpRGJWAxR
+db25fb3a8b52215441ebe0a5d6a4d4f1a8be5917
+zwf9dZ4pUPW
diff --git a/examples/json/json.sh b/examples/json/json.sh
index e9d0c9fe9..bee89cdba 100644
--- a/examples/json/json.sh
+++ b/examples/json/json.sh
@@ -13,9 +13,10 @@ a
{1 [apple peach]}
apple
{"apple":5,"lettuce":7}
+{1 [apple peach]}
# We've covered the basic of JSON in Go here, but check
-# out the [JSON and Go](http://blog.golang.org/2011/01/json-and-go.html)
-# blog post and [JSON package docs](http://golang.org/pkg/encoding/json/)
+# out the [JSON and Go](https://go.dev/blog/json)
+# blog post and [JSON package docs](https://pkg.go.dev/encoding/json)
# for more.
diff --git a/examples/logging/logging.go b/examples/logging/logging.go
new file mode 100644
index 000000000..18bbaf76d
--- /dev/null
+++ b/examples/logging/logging.go
@@ -0,0 +1,77 @@
+// The Go standard library provides straightforward
+// tools for outputting logs from Go programs, with
+// the [log](https://pkg.go.dev/log) package for
+// free-form output and the
+// [log/slog](https://pkg.go.dev/log/slog) package for
+// structured output.
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+
+ "log/slog"
+)
+
+func main() {
+
+ // Simply invoking functions like `Println` from the
+ // `log` package uses the _standard_ logger, which
+ // is already pre-configured for reasonable logging
+ // output to `os.Stderr`. Additional methods like
+ // `Fatal*` or `Panic*` will exit the program after
+ // logging.
+ log.Println("standard logger")
+
+ // Loggers can be configured with _flags_ to set
+ // their output format. By default, the standard
+ // logger has the `log.Ldate` and `log.Ltime` flags
+ // set, and these are collected in `log.LstdFlags`.
+ // We can change its flags to emit time with
+ // microsecond accuracy, for example.
+ log.SetFlags(log.LstdFlags | log.Lmicroseconds)
+ log.Println("with micro")
+
+ // It also supports emitting the file name and
+ // line from which the `log` function is called.
+ log.SetFlags(log.LstdFlags | log.Lshortfile)
+ log.Println("with file/line")
+
+ // It may be useful to create a custom logger and
+ // pass it around. When creating a new logger, we
+ // can set a _prefix_ to distinguish its output
+ // from other loggers.
+ mylog := log.New(os.Stdout, "my:", log.LstdFlags)
+ mylog.Println("from mylog")
+
+ // We can set the prefix
+ // on existing loggers (including the standard one)
+ // with the `SetPrefix` method.
+ mylog.SetPrefix("ohmy:")
+ mylog.Println("from mylog")
+
+ // Loggers can have custom output targets;
+ // any `io.Writer` works.
+ var buf bytes.Buffer
+ buflog := log.New(&buf, "buf:", log.LstdFlags)
+
+ // This call writes the log output into `buf`.
+ buflog.Println("hello")
+
+ // This will actually show it on standard output.
+ fmt.Print("from buflog:", buf.String())
+
+ // The `slog` package provides
+ // _structured_ log output. For example, logging
+ // in JSON format is straightforward.
+ jsonHandler := slog.NewJSONHandler(os.Stderr, nil)
+ myslog := slog.New(jsonHandler)
+ myslog.Info("hi there")
+
+ // In addition to the message, `slog` output can
+ // contain an arbitrary number of key=value
+ // pairs.
+ myslog.Info("hello again", "key", "val", "age", 25)
+}
diff --git a/examples/logging/logging.hash b/examples/logging/logging.hash
new file mode 100644
index 000000000..4d1c7a70e
--- /dev/null
+++ b/examples/logging/logging.hash
@@ -0,0 +1,2 @@
+38a7ef451859bb4c163df938b3a9d0e5ac293bef
+Qd0uCqBlYUn
diff --git a/examples/logging/logging.sh b/examples/logging/logging.sh
new file mode 100644
index 000000000..00bcc76c1
--- /dev/null
+++ b/examples/logging/logging.sh
@@ -0,0 +1,18 @@
+# Sample output; the date and time
+# emitted will depend on when the example ran.
+$ go run logging.go
+2023/08/22 10:45:16 standard logger
+2023/08/22 10:45:16.904141 with micro
+2023/08/22 10:45:16 logging.go:40: with file/line
+my:2023/08/22 10:45:16 from mylog
+ohmy:2023/08/22 10:45:16 from mylog
+from buflog:buf:2023/08/22 10:45:16 hello
+
+# These are wrapped for clarity of presentation
+# on the website; in reality they are emitted
+# on a single line.
+{"time":"2023-08-22T10:45:16.904166391-07:00",
+ "level":"INFO","msg":"hi there"}
+{"time":"2023-08-22T10:45:16.904178985-07:00",
+ "level":"INFO","msg":"hello again",
+ "key":"val","age":25}
diff --git a/examples/maps/maps.go b/examples/maps/maps.go
index 334627002..40f7c5873 100644
--- a/examples/maps/maps.go
+++ b/examples/maps/maps.go
@@ -1,9 +1,12 @@
-// _Maps_ are Go's built-in [associative data type](http://en.wikipedia.org/wiki/Associative_array)
+// _Maps_ are Go's built-in [associative data type](https://en.wikipedia.org/wiki/Associative_array)
// (sometimes called _hashes_ or _dicts_ in other languages).
package main
-import "fmt"
+import (
+ "fmt"
+ "maps"
+)
func main() {
@@ -22,7 +25,13 @@ func main() {
// Get a value for a key with `name[key]`.
v1 := m["k1"]
- fmt.Println("v1: ", v1)
+ fmt.Println("v1:", v1)
+
+ // If the key doesn't exist, the
+ // [zero value](https://go.dev/ref/spec#The_zero_value) of the
+ // value type is returned.
+ v3 := m["k3"]
+ fmt.Println("v3:", v3)
// The builtin `len` returns the number of key/value
// pairs when called on a map.
@@ -33,6 +42,11 @@ func main() {
delete(m, "k2")
fmt.Println("map:", m)
+ // To remove *all* key/value pairs from a map, use
+ // the `clear` builtin.
+ clear(m)
+ fmt.Println("map:", m)
+
// The optional second return value when getting a
// value from a map indicates if the key was present
// in the map. This can be used to disambiguate
@@ -47,4 +61,11 @@ func main() {
// the same line with this syntax.
n := map[string]int{"foo": 1, "bar": 2}
fmt.Println("map:", n)
+
+ // The `maps` package contains a number of useful
+ // utility functions for maps.
+ n2 := map[string]int{"foo": 1, "bar": 2}
+ if maps.Equal(n, n2) {
+ fmt.Println("n == n2")
+ }
}
diff --git a/examples/maps/maps.hash b/examples/maps/maps.hash
index 79caf58c9..32f844afe 100644
--- a/examples/maps/maps.hash
+++ b/examples/maps/maps.hash
@@ -1,2 +1,2 @@
-9e0e4535c99668b460c7175f8ff2edc2ccf58bec
-agK2Ro2i-Lu
+c8435b8cc754213b70c58c9a51dfa824c6f70dd7
+5jpkxJ2T0Lv
diff --git a/examples/maps/maps.sh b/examples/maps/maps.sh
index da7a841b3..f234e9f60 100644
--- a/examples/maps/maps.sh
+++ b/examples/maps/maps.sh
@@ -2,8 +2,11 @@
# printed with `fmt.Println`.
$ go run maps.go
map: map[k1:7 k2:13]
-v1: 7
+v1: 7
+v3: 0
len: 2
map: map[k1:7]
+map: map[]
prs: false
map: map[bar:2 foo:1]
+n == n2
diff --git a/examples/mutexes/mutexes.go b/examples/mutexes/mutexes.go
index 79b0c31c6..b6e5a14d4 100644
--- a/examples/mutexes/mutexes.go
+++ b/examples/mutexes/mutexes.go
@@ -1,85 +1,68 @@
// In the previous example we saw how to manage simple
// counter state using [atomic operations](atomic-counters).
-// For more complex state we can use a [mutex](http://en.wikipedia.org/wiki/Mutual_exclusion)
+// For more complex state we can use a [_mutex_](https://en.wikipedia.org/wiki/Mutual_exclusion)
// to safely access data across multiple goroutines.
package main
import (
"fmt"
- "math/rand"
"sync"
- "sync/atomic"
- "time"
)
-func main() {
-
- // For our example the `state` will be a map.
- var state = make(map[int]int)
-
- // This `mutex` will synchronize access to `state`.
- var mutex = &sync.Mutex{}
+// Container holds a map of counters; since we want to
+// update it concurrently from multiple goroutines, we
+// add a `Mutex` to synchronize access.
+// Note that mutexes must not be copied, so if this
+// `struct` is passed around, it should be done by
+// pointer.
+type Container struct {
+ mu sync.Mutex
+ counters map[string]int
+}
- // We'll keep track of how many read and write
- // operations we do.
- var readOps uint64
- var writeOps uint64
+func (c *Container) inc(name string) {
+ // Lock the mutex before accessing `counters`; unlock
+ // it at the end of the function using a [defer](defer)
+ // statement.
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.counters[name]++
+}
- // Here we start 100 goroutines to execute repeated
- // reads against the state, once per millisecond in
- // each goroutine.
- for r := 0; r < 100; r++ {
- go func() {
- total := 0
- for {
+func main() {
+ c := Container{
+ // Note that the zero value of a mutex is usable as-is, so no
+ // initialization is required here.
+ counters: map[string]int{"a": 0, "b": 0},
+ }
- // For each read we pick a key to access,
- // `Lock()` the `mutex` to ensure
- // exclusive access to the `state`, read
- // the value at the chosen key,
- // `Unlock()` the mutex, and increment
- // the `readOps` count.
- key := rand.Intn(5)
- mutex.Lock()
- total += state[key]
- mutex.Unlock()
- atomic.AddUint64(&readOps, 1)
+ var wg sync.WaitGroup
- // Wait a bit between reads.
- time.Sleep(time.Millisecond)
- }
- }()
+ // This function increments a named counter
+ // in a loop.
+ doIncrement := func(name string, n int) {
+ for range n {
+ c.inc(name)
+ }
}
- // We'll also start 10 goroutines to simulate writes,
- // using the same pattern we did for reads.
- for w := 0; w < 10; w++ {
- go func() {
- for {
- key := rand.Intn(5)
- val := rand.Intn(100)
- mutex.Lock()
- state[key] = val
- mutex.Unlock()
- atomic.AddUint64(&writeOps, 1)
- time.Sleep(time.Millisecond)
- }
- }()
- }
+ // Run several goroutines concurrently; note
+ // that they all access the same `Container`,
+ // and two of them access the same counter.
+ wg.Go(func() {
+ doIncrement("a", 10000)
+ })
- // Let the 10 goroutines work on the `state` and
- // `mutex` for a second.
- time.Sleep(time.Second)
+ wg.Go(func() {
+ doIncrement("a", 10000)
+ })
- // Take and report final operation counts.
- readOpsFinal := atomic.LoadUint64(&readOps)
- fmt.Println("readOps:", readOpsFinal)
- writeOpsFinal := atomic.LoadUint64(&writeOps)
- fmt.Println("writeOps:", writeOpsFinal)
+ wg.Go(func() {
+ doIncrement("b", 10000)
+ })
- // With a final lock of `state`, show how it ended up.
- mutex.Lock()
- fmt.Println("state:", state)
- mutex.Unlock()
+ // Wait for the goroutines to finish
+ wg.Wait()
+ fmt.Println(c.counters)
}
diff --git a/examples/mutexes/mutexes.hash b/examples/mutexes/mutexes.hash
index 95b8135f1..68900ea9b 100644
--- a/examples/mutexes/mutexes.hash
+++ b/examples/mutexes/mutexes.hash
@@ -1,2 +1,2 @@
-7cb6349117087c78ddb71c240e988ec8281c8952
-0WEmOOjoCjp
+5271a346794ed097df21fb0f2b2d3d01c9bb361c
+u0VAVSWRlU0
diff --git a/examples/mutexes/mutexes.sh b/examples/mutexes/mutexes.sh
index 185f4fafa..d379c1f22 100644
--- a/examples/mutexes/mutexes.sh
+++ b/examples/mutexes/mutexes.sh
@@ -1,10 +1,7 @@
-# Running the program shows that we executed about
-# 90,000 total operations against our `mutex`-synchronized
-# `state`.
+# Running the program shows that the counters
+# updated as expected.
$ go run mutexes.go
-readOps: 83285
-writeOps: 8320
-state: map[1:97 4:53 0:33 2:15 3:2]
+map[a:20000 b:10000]
# Next we'll look at implementing this same state
# management task using only goroutines and channels.
diff --git a/examples/panic/panic.go b/examples/panic/panic.go
index 27e72f094..f1e750148 100644
--- a/examples/panic/panic.go
+++ b/examples/panic/panic.go
@@ -5,7 +5,10 @@
package main
-import "os"
+import (
+ "os"
+ "path/filepath"
+)
func main() {
@@ -18,7 +21,8 @@ func main() {
// returns an error value that we don't know how to
// (or want to) handle. Here's an example of
// `panic`king if we get an unexpected error when creating a new file.
- _, err := os.Create("/tmp/file")
+ path := filepath.Join(os.TempDir(), "file")
+ _, err := os.Create(path)
if err != nil {
panic(err)
}
diff --git a/examples/panic/panic.hash b/examples/panic/panic.hash
index 8223707dd..f433b9a04 100644
--- a/examples/panic/panic.hash
+++ b/examples/panic/panic.hash
@@ -1,2 +1,2 @@
-d1d154be95ba37739e3598a9195b6ae0a427bc80
-9-2vCvRuhmE
+39f5cb04eb753e4c35cfc6358f24d0b5985c8556
+Z57OSC0ASwn
diff --git a/examples/panic/panic.sh b/examples/panic/panic.sh
index a851be97f..c5a7e1d8c 100644
--- a/examples/panic/panic.sh
+++ b/examples/panic/panic.sh
@@ -1,6 +1,11 @@
# Running this program will cause it to panic, print
# an error message and goroutine traces, and exit with
# a non-zero status.
+
+# When first panic in `main` fires, the program exits
+# without reaching the rest of the code. If you'd like
+# to see the program try to create a temp file, comment
+# the first panic out.
$ go run panic.go
panic: a problem
diff --git a/examples/pointers/pointers.go b/examples/pointers/pointers.go
index 55749978f..1a24906ce 100644
--- a/examples/pointers/pointers.go
+++ b/examples/pointers/pointers.go
@@ -1,4 +1,4 @@
-// Go supports pointers,
+// Go supports pointers,
// allowing you to pass references to values and records
// within your program.
diff --git a/examples/pointers/pointers.hash b/examples/pointers/pointers.hash
index 455774fb3..b67064b00 100644
--- a/examples/pointers/pointers.hash
+++ b/examples/pointers/pointers.hash
@@ -1,2 +1,2 @@
-c727916063ddc3e99199cd24bfbde37ff301c0b4
-oimmXypnAcs
+7f9855cfb983efc07415117e2be734f55a6bb64b
+OlWCLpxAyBz
diff --git a/examples/random-numbers/random-numbers.go b/examples/random-numbers/random-numbers.go
index ebb6a8ccd..d63d656cc 100644
--- a/examples/random-numbers/random-numbers.go
+++ b/examples/random-numbers/random-numbers.go
@@ -1,21 +1,20 @@
-// Go's `math/rand` package provides
-// [pseudorandom number](http://en.wikipedia.org/wiki/Pseudorandom_number_generator)
+// Go's `math/rand/v2` package provides
+// [pseudorandom number](https://en.wikipedia.org/wiki/Pseudorandom_number_generator)
// generation.
package main
import (
"fmt"
- "math/rand"
- "time"
+ "math/rand/v2"
)
func main() {
- // For example, `rand.Intn` returns a random `int` n,
+ // For example, `rand.IntN` returns a random `int` n,
// `0 <= n < 100`.
- fmt.Print(rand.Intn(100), ",")
- fmt.Print(rand.Intn(100))
+ fmt.Print(rand.IntN(100), ",")
+ fmt.Print(rand.IntN(100))
fmt.Println()
// `rand.Float64` returns a `float64` `f`,
@@ -28,29 +27,21 @@ func main() {
fmt.Print((rand.Float64() * 5) + 5)
fmt.Println()
- // The default number generator is deterministic, so it'll
- // produce the same sequence of numbers each time by default.
- // To produce varying sequences, give it a seed that changes.
- // Note that this is not safe to use for random numbers you
- // intend to be secret, use `crypto/rand` for those.
- s1 := rand.NewSource(time.Now().UnixNano())
- r1 := rand.New(s1)
-
- // Call the resulting `rand.Rand` just like the
- // functions on the `rand` package.
- fmt.Print(r1.Intn(100), ",")
- fmt.Print(r1.Intn(100))
- fmt.Println()
-
- // If you seed a source with the same number, it
- // produces the same sequence of random numbers.
- s2 := rand.NewSource(42)
+ // If you want a known seed, create a new
+ // `rand.Source` and pass it into the `New`
+ // constructor. `NewPCG` creates a new
+ // [PCG](https://en.wikipedia.org/wiki/Permuted_congruential_generator)
+ // source that requires a seed of two `uint64`
+ // numbers.
+ s2 := rand.NewPCG(42, 1024)
r2 := rand.New(s2)
- fmt.Print(r2.Intn(100), ",")
- fmt.Print(r2.Intn(100))
+ fmt.Print(r2.IntN(100), ",")
+ fmt.Print(r2.IntN(100))
fmt.Println()
- s3 := rand.NewSource(42)
+
+ s3 := rand.NewPCG(42, 1024)
r3 := rand.New(s3)
- fmt.Print(r3.Intn(100), ",")
- fmt.Print(r3.Intn(100))
+ fmt.Print(r3.IntN(100), ",")
+ fmt.Print(r3.IntN(100))
+ fmt.Println()
}
diff --git a/examples/random-numbers/random-numbers.hash b/examples/random-numbers/random-numbers.hash
index 907e93b44..e005e5f7c 100644
--- a/examples/random-numbers/random-numbers.hash
+++ b/examples/random-numbers/random-numbers.hash
@@ -1,2 +1,2 @@
-102041ca421268afbd4b4e7687386bb65a8c7965
-PGklfJzErTN
+76b8f86171ffcf9e7d5781fdf50c050a824acd9b
+TkgmNAl8euK
diff --git a/examples/random-numbers/random-numbers.sh b/examples/random-numbers/random-numbers.sh
index 67c37a8ec..6c9b47170 100644
--- a/examples/random-numbers/random-numbers.sh
+++ b/examples/random-numbers/random-numbers.sh
@@ -1,12 +1,12 @@
+# Some of the generated numbers may be
+# different when you run the sample.
$ go run random-numbers.go
-81,87
-0.6645600532184904
-7.123187485356329,8.434115364335547
-0,28
-5,87
-5,87
+68,56
+0.8090228139659177
+5.840125017402497,6.937056298890035
+94,49
+94,49
-
-# See the [`math/rand`](http://golang.org/pkg/math/rand/)
+# See the [`math/rand/v2`](https://pkg.go.dev/math/rand/v2)
# package docs for references on other random quantities
# that Go can provide.
diff --git a/examples/range/range.go b/examples/range-over-built-in-types/range-over-built-in-types.go
similarity index 81%
rename from examples/range/range.go
rename to examples/range-over-built-in-types/range-over-built-in-types.go
index 011af674e..6a55eb148 100644
--- a/examples/range/range.go
+++ b/examples/range-over-built-in-types/range-over-built-in-types.go
@@ -1,6 +1,7 @@
-// _range_ iterates over elements in a variety of data
-// structures. Let's see how to use `range` with some
-// of the data structures we've already learned.
+// _range_ iterates over elements in a variety of
+// built-in data structures. Let's see how to
+// use `range` with some of the data structures
+// we've already learned.
package main
@@ -42,6 +43,8 @@ func main() {
// `range` on strings iterates over Unicode code
// points. The first value is the starting byte index
// of the `rune` and the second the `rune` itself.
+ // See [Strings and Runes](strings-and-runes) for more
+ // details.
for i, c := range "go" {
fmt.Println(i, c)
}
diff --git a/examples/range-over-built-in-types/range-over-built-in-types.hash b/examples/range-over-built-in-types/range-over-built-in-types.hash
new file mode 100644
index 000000000..ad6a64216
--- /dev/null
+++ b/examples/range-over-built-in-types/range-over-built-in-types.hash
@@ -0,0 +1,2 @@
+3d8c61f02f98892be9d3ff25d48da0bfb31bbd25
+S171w0PjgsD
diff --git a/examples/range/range.sh b/examples/range-over-built-in-types/range-over-built-in-types.sh
similarity index 63%
rename from examples/range/range.sh
rename to examples/range-over-built-in-types/range-over-built-in-types.sh
index e3f40d8a9..261634293 100644
--- a/examples/range/range.sh
+++ b/examples/range-over-built-in-types/range-over-built-in-types.sh
@@ -1,4 +1,4 @@
-$ go run range.go
+$ go run range-over-built-in-types.go
sum: 9
index: 1
a -> apple
diff --git a/examples/range-over-channels/range-over-channels.go b/examples/range-over-channels/range-over-channels.go
index d8aa729fe..356c1289c 100644
--- a/examples/range-over-channels/range-over-channels.go
+++ b/examples/range-over-channels/range-over-channels.go
@@ -1,4 +1,4 @@
-// In a [previous](range) example we saw how `for` and
+// In a [previous](range-over-built-in-types) example we saw how `for` and
// `range` provide iteration over basic data structures.
// We can also use this syntax to iterate over
// values received from a channel.
diff --git a/examples/range-over-channels/range-over-channels.hash b/examples/range-over-channels/range-over-channels.hash
index b3b135cfe..89918ad06 100644
--- a/examples/range-over-channels/range-over-channels.hash
+++ b/examples/range-over-channels/range-over-channels.hash
@@ -1,2 +1,2 @@
-1812ab409c07ea4209106ee4c0d2eb597fccd717
-yQMclmwOYs9
+446dea3a7cb9e16ce3e17a6649c719e764936740
+8vAhX6eX1wy
diff --git a/examples/range-over-iterators/range-over-iterators.go b/examples/range-over-iterators/range-over-iterators.go
new file mode 100644
index 000000000..ba65dd6b5
--- /dev/null
+++ b/examples/range-over-iterators/range-over-iterators.go
@@ -0,0 +1,107 @@
+// Starting with version 1.23, Go has added support for
+// [iterators](https://go.dev/blog/range-functions),
+// which lets us range over pretty much anything!
+
+package main
+
+import (
+ "fmt"
+ "iter"
+ "slices"
+ "strings"
+)
+
+// Let's look at the `List` type from the
+// [previous example](generics) again. In that example
+// we had an `AllElements` method that returned a slice
+// of all elements in the list. With Go iterators, we
+// can do it better - as shown below.
+type List[T any] struct {
+ head, tail *element[T]
+}
+
+type element[T any] struct {
+ next *element[T]
+ val T
+}
+
+func (lst *List[T]) Push(v T) {
+ if lst.tail == nil {
+ lst.head = &element[T]{val: v}
+ lst.tail = lst.head
+ } else {
+ lst.tail.next = &element[T]{val: v}
+ lst.tail = lst.tail.next
+ }
+}
+
+// All returns an _iterator_, which in Go is a function
+// with a [special signature](https://pkg.go.dev/iter#Seq).
+func (lst *List[T]) All() iter.Seq[T] {
+ return func(yield func(T) bool) {
+ // The iterator function takes another function as
+ // a parameter, called `yield` by convention (but
+ // the name can be arbitrary). It will call `yield` for
+ // every element we want to iterate over, and note `yield`'s
+ // return value for a potential early termination.
+ for e := lst.head; e != nil; e = e.next {
+ if !yield(e.val) {
+ return
+ }
+ }
+ }
+}
+
+// Iteration doesn't require an underlying data structure,
+// and doesn't even have to be finite! Here's a function
+// returning an iterator over Fibonacci numbers: it keeps
+// running as long as `yield` keeps returning `true`.
+func genFib() iter.Seq[int] {
+ return func(yield func(int) bool) {
+ a, b := 0, 1
+
+ for {
+ if !yield(a) {
+ return
+ }
+ a, b = b, a+b
+ }
+ }
+}
+
+func main() {
+ lst := List[int]{}
+ lst.Push(10)
+ lst.Push(13)
+ lst.Push(23)
+
+ // Since `List.All` returns an iterator, we can use it
+ // in a regular `range` loop.
+ for e := range lst.All() {
+ fmt.Println(e)
+ }
+
+ // Packages like [slices](https://pkg.go.dev/slices) have
+ // a number of useful functions to work with iterators.
+ // For example, `Collect` takes any iterator and collects
+ // all its values into a slice.
+ all := slices.Collect(lst.All())
+ fmt.Println("all:", all)
+
+ // Standard library packages now expose iterator helpers
+ // too. For example, `strings.SplitSeq` iterates over parts
+ // of a byte slice without first building a result slice.
+ for part := range strings.SplitSeq("go-by-example", "-") {
+ fmt.Printf("part: %s\n", part)
+ }
+
+ for n := range genFib() {
+
+ // Once the loop hits `break` or an early return, the `yield` function
+ // passed to the iterator will return `false`.
+ if n >= 10 {
+ break
+ }
+ fmt.Println(n)
+ }
+}
diff --git a/examples/range-over-iterators/range-over-iterators.hash b/examples/range-over-iterators/range-over-iterators.hash
new file mode 100644
index 000000000..a75658d91
--- /dev/null
+++ b/examples/range-over-iterators/range-over-iterators.hash
@@ -0,0 +1,2 @@
+d7e65d4e52957e845b0e2ca925af9ce5eff43148
+lHX3uDqdfUB
diff --git a/examples/range-over-iterators/range-over-iterators.sh b/examples/range-over-iterators/range-over-iterators.sh
new file mode 100644
index 000000000..02c9a0046
--- /dev/null
+++ b/examples/range-over-iterators/range-over-iterators.sh
@@ -0,0 +1,15 @@
+$ go run range-over-iterators.go
+10
+13
+23
+all: [10 13 23]
+part: go
+part: by
+part: example
+0
+1
+1
+2
+3
+5
+8
diff --git a/examples/range/range.hash b/examples/range/range.hash
deleted file mode 100644
index f6e5a86ab..000000000
--- a/examples/range/range.hash
+++ /dev/null
@@ -1,2 +0,0 @@
-c7d9ae9ed081fb4bbf27ef45242fbb39bbae3d4c
-pdZOtv4g-7J
diff --git a/examples/rate-limiting/rate-limiting.go b/examples/rate-limiting/rate-limiting.go
index c32483d3d..64ea99697 100644
--- a/examples/rate-limiting/rate-limiting.go
+++ b/examples/rate-limiting/rate-limiting.go
@@ -1,4 +1,4 @@
-// [Rate limiting](http://en.wikipedia.org/wiki/Rate_limiting)
+// [_Rate limiting_](https://en.wikipedia.org/wiki/Rate_limiting)
// is an important mechanism for controlling resource
// utilization and maintaining quality of service. Go
// elegantly supports rate limiting with goroutines,
@@ -44,7 +44,7 @@ func main() {
burstyLimiter := make(chan time.Time, 3)
// Fill up the channel to represent allowed bursting.
- for i := 0; i < 3; i++ {
+ for range 3 {
burstyLimiter <- time.Now()
}
diff --git a/examples/rate-limiting/rate-limiting.hash b/examples/rate-limiting/rate-limiting.hash
index 813cbef2a..cefddcbee 100644
--- a/examples/rate-limiting/rate-limiting.hash
+++ b/examples/rate-limiting/rate-limiting.hash
@@ -1,2 +1,2 @@
-c2d4dd4c2121e61395db186e3f15ce8cb3acf643
-20c_m1AtOEI
+c1eee474067ad718e57df5c55242ba4711e7bcb7
+y9V3goQfy5m
diff --git a/examples/reading-files/reading-files.go b/examples/reading-files/reading-files.go
index 49387a671..a6c8b46da 100644
--- a/examples/reading-files/reading-files.go
+++ b/examples/reading-files/reading-files.go
@@ -8,8 +8,8 @@ import (
"bufio"
"fmt"
"io"
- "io/ioutil"
"os"
+ "path/filepath"
)
// Reading files requires checking most calls for errors.
@@ -24,14 +24,15 @@ func main() {
// Perhaps the most basic file reading task is
// slurping a file's entire contents into memory.
- dat, err := ioutil.ReadFile("/tmp/dat")
+ path := filepath.Join(os.TempDir(), "dat")
+ dat, err := os.ReadFile(path)
check(err)
fmt.Print(string(dat))
// You'll often want more control over how and what
// parts of a file are read. For these tasks, start
// by `Open`ing a file to obtain an `os.File` value.
- f, err := os.Open("/tmp/dat")
+ f, err := os.Open(path)
check(err)
// Read some bytes from the beginning of the file.
@@ -44,7 +45,7 @@ func main() {
// You can also `Seek` to a known location in the file
// and `Read` from there.
- o2, err := f.Seek(6, 0)
+ o2, err := f.Seek(6, io.SeekStart)
check(err)
b2 := make([]byte, 2)
n2, err := f.Read(b2)
@@ -52,20 +53,29 @@ func main() {
fmt.Printf("%d bytes @ %d: ", n2, o2)
fmt.Printf("%v\n", string(b2[:n2]))
+ // Other methods of seeking are relative to the
+ // current cursor position,
+ _, err = f.Seek(2, io.SeekCurrent)
+ check(err)
+
+ // and relative to the end of the file.
+ _, err = f.Seek(-4, io.SeekEnd)
+ check(err)
+
// The `io` package provides some functions that may
// be helpful for file reading. For example, reads
// like the ones above can be more robustly
// implemented with `ReadAtLeast`.
- o3, err := f.Seek(6, 0)
+ o3, err := f.Seek(6, io.SeekStart)
check(err)
b3 := make([]byte, 2)
n3, err := io.ReadAtLeast(f, b3, 2)
check(err)
fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
- // There is no built-in rewind, but `Seek(0, 0)`
- // accomplishes this.
- _, err = f.Seek(0, 0)
+ // There is no built-in rewind, but
+ // `Seek(0, io.SeekStart)` accomplishes this.
+ _, err = f.Seek(0, io.SeekStart)
check(err)
// The `bufio` package implements a buffered
diff --git a/examples/reading-files/reading-files.hash b/examples/reading-files/reading-files.hash
index 2933d50c9..a6f8c50f7 100644
--- a/examples/reading-files/reading-files.hash
+++ b/examples/reading-files/reading-files.hash
@@ -1,2 +1,2 @@
-3420958bafd67fd997481d1ada288566666343c7
-kF0cDC0drsX
+f4a5063dc6db22beac95c6b60a8a76e3422e8cf4
+J710-KJyC8z
diff --git a/examples/recover/recover.go b/examples/recover/recover.go
new file mode 100644
index 000000000..7cf728720
--- /dev/null
+++ b/examples/recover/recover.go
@@ -0,0 +1,41 @@
+// Go makes it possible to _recover_ from a panic, by
+// using the `recover` built-in function. A `recover` can
+// stop a `panic` from aborting the program and let it
+// continue with execution instead.
+
+// An example of where this can be useful: a server
+// wouldn't want to crash if one of the client connections
+// exhibits a critical error. Instead, the server would
+// want to close that connection and continue serving
+// other clients. In fact, this is what Go's `net/http`
+// does by default for HTTP servers.
+
+package main
+
+import "fmt"
+
+// This function panics.
+func mayPanic() {
+ panic("a problem")
+}
+
+func main() {
+ // `recover` must be called within a deferred function.
+ // When the enclosing function panics, the defer will
+ // activate and a `recover` call within it will catch
+ // the panic.
+ defer func() {
+ if r := recover(); r != nil {
+ // The return value of `recover` is the error raised in
+ // the call to `panic`.
+ fmt.Println("Recovered. Error:\n", r)
+ }
+ }()
+
+ mayPanic()
+
+ // This code will not run, because `mayPanic` panics.
+ // The execution of `main` stops at the point of the
+ // panic and resumes in the deferred closure.
+ fmt.Println("After mayPanic()")
+}
diff --git a/examples/recover/recover.hash b/examples/recover/recover.hash
new file mode 100644
index 000000000..4aa77d592
--- /dev/null
+++ b/examples/recover/recover.hash
@@ -0,0 +1,2 @@
+053ecbddb4f4a1d881aa40086de99da4e78b9990
+Sk-SVdofEIZ
diff --git a/examples/recover/recover.sh b/examples/recover/recover.sh
new file mode 100644
index 000000000..686e75990
--- /dev/null
+++ b/examples/recover/recover.sh
@@ -0,0 +1,3 @@
+$ go run recover.go
+Recovered. Error:
+ a problem
diff --git a/examples/recursion/recursion.go b/examples/recursion/recursion.go
index a88b1e59e..17d9c1dce 100644
--- a/examples/recursion/recursion.go
+++ b/examples/recursion/recursion.go
@@ -1,6 +1,6 @@
// Go supports
-// recursive functions.
-// Here's a classic factorial example.
+// recursive functions.
+// Here's a classic example.
package main
@@ -17,4 +17,21 @@ func fact(n int) int {
func main() {
fmt.Println(fact(7))
+
+ // Anonymous functions can also be recursive, but this requires
+ // explicitly declaring a variable with `var` to store
+ // the function before it's defined.
+ var fib func(n int) int
+
+ fib = func(n int) int {
+ if n < 2 {
+ return n
+ }
+
+ // Since `fib` was previously declared in `main`, Go
+ // knows which function to call with `fib` here.
+ return fib(n-1) + fib(n-2)
+ }
+
+ fmt.Println(fib(7))
}
diff --git a/examples/recursion/recursion.hash b/examples/recursion/recursion.hash
index ac2db783c..832d7fc9b 100644
--- a/examples/recursion/recursion.hash
+++ b/examples/recursion/recursion.hash
@@ -1,2 +1,2 @@
-9bfb2f870007082835a3c0efaac9aa1c3bc2c15c
-smWim1q9ofu
+5787b4a187dc208dcdae43c7fdc0ba19b821ed94
+k4IRATLn9cE
diff --git a/examples/recursion/recursion.sh b/examples/recursion/recursion.sh
index 53b8e15a8..ac854846a 100644
--- a/examples/recursion/recursion.sh
+++ b/examples/recursion/recursion.sh
@@ -1,2 +1,3 @@
$ go run recursion.go
5040
+13
diff --git a/examples/regular-expressions/regular-expressions.go b/examples/regular-expressions/regular-expressions.go
index f05d26955..aa7bf75b8 100644
--- a/examples/regular-expressions/regular-expressions.go
+++ b/examples/regular-expressions/regular-expressions.go
@@ -1,4 +1,4 @@
-// Go offers built-in support for [regular expressions](http://en.wikipedia.org/wiki/Regular_expression).
+// Go offers built-in support for [regular expressions](https://en.wikipedia.org/wiki/Regular_expression).
// Here are some examples of common regexp-related tasks
// in Go.
@@ -31,7 +31,7 @@ func main() {
// This also finds the first match but returns the
// start and end indexes for the match instead of the
// matching text.
- fmt.Println(r.FindStringIndex("peach punch"))
+ fmt.Println("idx:", r.FindStringIndex("peach punch"))
// The `Submatch` variants include information about
// both the whole-pattern matches and the submatches
@@ -50,7 +50,7 @@ func main() {
// These `All` variants are available for the other
// functions we saw above as well.
- fmt.Println(r.FindAllStringSubmatchIndex(
+ fmt.Println("all:", r.FindAllStringSubmatchIndex(
"peach punch pinch", -1))
// Providing a non-negative integer as the second
@@ -70,7 +70,7 @@ func main() {
// returning an error, which makes it safer to use for
// global variables.
r = regexp.MustCompile("p([a-z]+)ch")
- fmt.Println(r)
+ fmt.Println("regexp:", r)
// The `regexp` package can also be used to replace
// subsets of strings with other values.
diff --git a/examples/regular-expressions/regular-expressions.hash b/examples/regular-expressions/regular-expressions.hash
index bffd78787..8650e3bf2 100644
--- a/examples/regular-expressions/regular-expressions.hash
+++ b/examples/regular-expressions/regular-expressions.hash
@@ -1,2 +1,2 @@
-c0dd720036ac70269ce233bf47c5d6aefd43161f
-LEKGY_d3Nu_P
+7fd60a9497546cb5c84242276ed79aecbde7e950
+fI2YIfYsCaL
diff --git a/examples/regular-expressions/regular-expressions.sh b/examples/regular-expressions/regular-expressions.sh
index 1f3882c34..afdab0d68 100644
--- a/examples/regular-expressions/regular-expressions.sh
+++ b/examples/regular-expressions/regular-expressions.sh
@@ -1,17 +1,17 @@
-$ go run regular-expressions.go
+$ go run regular-expressions.go
true
true
peach
-[0 5]
+idx: [0 5]
[peach ea]
[0 5 1 3]
[peach punch pinch]
-[[0 5 1 3] [6 11 7 9] [12 17 13 15]]
+all: [[0 5 1 3] [6 11 7 9] [12 17 13 15]]
[peach punch]
true
-p([a-z]+)ch
+regexp: p([a-z]+)ch
a Sorry, we couldn't find that! Check out the home page?
- + + +