diff --git a/.env b/.env new file mode 100644 index 0000000..c436e88 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +CANONICAL_HOST=127.0.0.1 +FORCE_HTTPS=0 diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..4d0c0cf --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gobyexample diff --git a/README.md b/README.md index 78fab16..f3165e6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Go by Example -Content and toolchain for [Go by Example](https://gobyexample.com). +Content, toolchain, and web server for [Go by Example](https://gobyexample.com). ### Overview @@ -10,10 +10,9 @@ comments from source files in `examples` and rendering that data via the site `templates`. The programs implementing this build process are in `tools`. -The build process produces a directory of static files -suitable for serving by any modern HTTP server. The -Go by Example site is served by a -[lightweight Go server](https://github.com/mmcgrana/gobyexample-server). +The build process produces a directory of static files - +`public` - suitable for serving by any modern HTTP server. +We include a lightweight Go server in `server.go`. ### Building @@ -22,7 +21,7 @@ To build the site: ```console $ tools/build -$ open site/index.html +$ open public/index.html ``` To build continuously in a loop: @@ -40,16 +39,53 @@ $ export PATH="$HOME/repos/pygments:$PATH" ``` -### Serving +### Local Deploy -The site is served by the [gobyexample-server](https://github.com/mmcgrana/gobyexample-server) -tool. To export to this tool: - -```console -$ SITEDIR=../gobyexample-server/public tool/build +```bash +$ mkdir -p $GOPATH/src/github.com/mmcgrana +$ cd $GOPATH/src/github.com/mmcgrana +$ git clone git@github.com:mmcgrana/gobyexaple.git +$ cd gobyexample +$ go get +$ foreman start +$ foreman open ``` +### Platform Deploy + +Basic setup: + +```bash +$ export DEPLOY=$USER +$ heroku create gobyexample-$DEPLOY -r $DEPLOY +$ heroku config:add -r $DEPLOY \ + BUILDPACK_URL=https://github.com/kr/heroku-buildpack-go.git -r $DEPLOY \ + CANONICAL_HOST=gobyexample-$DEPLOY.herokuapp.com -r $DEPLOY \ + FORCE_HTTPS=1 \ + AUTH=go:byexample +$ git push $DEPLOY master +$ heroku open -r $DEPLOY +``` + +Add a domain + SSL: + +```bash +$ heroku domains:add $DOMAIN +$ heroku addons:add ssl -r $DEPLOY +# order ssl cert for domain +$ cat > /tmp/server.key +$ cat > /tmp/server.crt.orig +$ cat /tmp/server.crt.orig /tmp/rapidssl_bundle.pem > /tmp/server.crt +$ heroku certs:add /tmp/server.crt /tmp/server.key -r $DEPLOY +# add ALIAS record from domain to ssl endpoint dns +$ heroku config:add CANONICAL_HOST=$DOMAIN -r $DEPLOY +$ heroku open -r $DEPLOY +``` + + + + ### License This work is licensed under a diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..2c5c604 --- /dev/null +++ b/public/404.html @@ -0,0 +1,29 @@ + + + + + Go by Example: Not Found + + + + +
+

Go by Example

+

Sorry, we couldn't find that! Check out the home page?

+ +
+ + diff --git a/public/arrays b/public/arrays new file mode 100644 index 0000000..a371474 --- /dev/null +++ b/public/arrays @@ -0,0 +1,195 @@ + + + + + Go by Example: Arrays + + + + +
+

Go by Example: Arrays

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In Go, an array is a numbered sequence of elements of a +specific length.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Here we create an array a that will hold exactly +5 ints. The type of elements and length are both +part of the array’s type. By default an array is +zero-valued, which for ints means 0s.

+ +
+
    var a [5]int
+    fmt.Println("emp:", a)
+
+ +
+

We can set a value at an index using the +array[index] = value syntax, and get a value with +array[index].

+ +
+
    a[4] = 100
+    fmt.Println("set:", a)
+    fmt.Println("get:", a[4])
+
+ +
+

The builtin len returns the length of an array.

+ +
+
    fmt.Println("len:", len(a))
+
+ +
+

Use this syntax to declare and initalize an array +in one line.

+ +
+
    b := [5]int{1, 2, 3, 4, 5}
+    fmt.Println("dcl:", b)
+
+ +
+

Array types are one-dimensional, but you can +compose types to build multi-dimensional data +structures.

+ +
+
    var twoD [2][3]int
+    for i := 0; i < 2; i++ {
+        for j := 0; j < 3; j++ {
+            twoD[i][j] = i + j
+        }
+    }
+    fmt.Println("2d: ", twoD)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Note that arrays appear in the form [v1 v2 v3 ...] +when printed with fmt.Println.

+ +
+
$ go run arrays.go
+emp: [0 0 0 0 0]
+set: [0 0 0 0 100]
+get: 100
+len: 5
+dcl: [1 2 3 4 5]
+2d:  [[0 1 2] [1 2 3]]
+
+ +
+

You’ll see slices much more often than arrays in +typical Go. We’ll look at slices next.

+ +
+ +
+ + +

+ Next example: Slices. +

+ + +
+ + diff --git a/public/atomic-counters b/public/atomic-counters new file mode 100644 index 0000000..a68e139 --- /dev/null +++ b/public/atomic-counters @@ -0,0 +1,207 @@ + + + + + Go by Example: Atomic Counters + + + + +
+

Go by Example: Atomic Counters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

The primary mechanism for managing state in Go is +communication over channels. We saw this for example +with worker pools. There are a few other +options for managing state though. Here we’ll +look at using the sync/atomic package for atomic +counters accessed by multiple goroutines.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+import "sync/atomic"
+
+ +
+ + +
func main() {
+
+ +
+

We’ll use an unsigned integer to represent our +(always-positive) counter.

+ +
+
    var ops uint64 = 0
+
+ +
+

To simulate concurrent updates, we’ll start 50 +goroutines that each increment the counter about +once a millisecond.

+ +
+
    for i := 0; i < 50; i++ {
+        go func() {
+            for {
+                time.Sleep(time.Millisecond)
+
+ +
+

To atomically increment the counter we +use AddUint64, giving it the memory +address of our ops counter with the +& syntax.

+ +
+
                atomic.AddUint64(&ops, 1)
+            }
+        }()
+    }
+
+ +
+

Wait a second to allow some ops to accumulate.

+ +
+
    time.Sleep(time.Second)
+
+ +
+

In order to safely use the counter while it’s still +being updated by other goroutines, we extract a +copy of the current value into opsFinal via +LoadUint64. As above we need to give this +function the memory address &ops from which to +fetch the value.

+ +
+
    opsFinal := atomic.LoadUint64(&ops)
+    fmt.Println("ops:", opsFinal)
+}
+
+ +
+

Next we’ll look at another approach to managing state: +mutexes.

+ +
+ +
+ + + + + + + + + + + + + +
+

Running the program shows that we executed about +40,000 operations.

+ +
+
$ go run atomic-counters.go
+ops: 40200
+
+ +
+

Next we’ll look at mutexes, another tool for managing +state.

+ +
+ +
+ + +

+ Next example: Mutexes. +

+ + +
+ + diff --git a/public/base64-encoding b/public/base64-encoding new file mode 100644 index 0000000..1ba5f17 --- /dev/null +++ b/public/base64-encoding @@ -0,0 +1,179 @@ + + + + + Go by Example: Base64 Encoding + + + + +
+

Go by Example: Base64 Encoding

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go provides built-in support for base64 +encoding/decoding.

+ +
+ +
+ + +
package main
+
+ +
+

This syntax imports the encoding/base64 package with +the b64 name instead of the default base64. It’ll +save us some space below.

+ +
+
import b64 "encoding/base64"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Here’s the string we’ll encode/decode.

+ +
+
    data := "abc123!?$*&()'-=@~"
+
+ +
+

Go supports both standard and URL-compatible +base64. Here’s how to encode using the standard +encoder. The encoder requires a []byte so we +cast our string to that type.

+ +
+
    sEnc := b64.StdEncoding.EncodeToString([]byte(data))
+    fmt.Println(sEnc)
+
+ +
+

Decoding may return an error, which you can check +if you don’t already know the input to be +well-formed.

+ +
+
    sDec, _ := b64.StdEncoding.DecodeString(sEnc)
+    fmt.Println(string(sDec))
+    fmt.Println()
+
+ +
+

This encodes/decodes using a URL-compatible base64 +format.

+ +
+
    uEnc := b64.URLEncoding.EncodeToString([]byte(data))
+    fmt.Println(uEnc)
+    uDec, _ := b64.URLEncoding.DecodeString(uEnc)
+    fmt.Println(string(uDec))
+}
+
+ +
+ + + + + + + + + + + + + +
+

The string encodes to slightly different values with the +standard and URL base64 encoders (trailing + vs -) +but they both decode to the original string as desired.

+ +
+
$ go run base64-encoding.sh
+YWJjMTIzIT8kKiYoKSctPUB+
+abc123!?$*&()'-=@~
+
+ +
+ + +
YWJjMTIzIT8kKiYoKSctPUB-
+abc123!?$*&()'-=@~
+
+ +
+ + +

+ Next example: Reading Files. +

+ + +
+ + diff --git a/public/channel-buffering b/public/channel-buffering new file mode 100644 index 0000000..ee0e9b4 --- /dev/null +++ b/public/channel-buffering @@ -0,0 +1,145 @@ + + + + + Go by Example: Channel Buffering + + + + +
+

Go by Example: Channel Buffering

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

By default channels are unbuffered, meaning that they +will only accept sends (chan <-) if there is a +corresponding receive (<- chan) ready to receive the +sent value. Buffered channels accept a limited +number of values without a corresponding receiver for +those values.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Here we make a channel of strings buffering up to +2 values.

+ +
+
    messages := make(chan string, 2)
+
+ +
+

Because this channel is buffered, we can send these +values into the channel without a corresponding +concurrent receive.

+ +
+
    messages <- "buffered"
+    messages <- "channel"
+
+ +
+

Later we can receive these two values as usual.

+ +
+
    fmt.Println(<-messages)
+    fmt.Println(<-messages)
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run channel-buffering.go 
+buffered
+channel
+
+ +
+ + +

+ Next example: Channel Synchronization. +

+ + +
+ + diff --git a/public/channel-directions b/public/channel-directions new file mode 100644 index 0000000..0c9831f --- /dev/null +++ b/public/channel-directions @@ -0,0 +1,138 @@ + + + + + Go by Example: Channel Directions + + + + +
+

Go by Example: Channel Directions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

When using channels as function parameters, you can +specify if a channel is meant to only send or receive +values. This specificity increases the type-safety of +the program.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

This ping function only accepts a channel for sending +values. It would be a compile-time error to try to +receive on this channel.

+ +
+
func ping(pings chan<- string, msg string) {
+    pings <- msg
+}
+
+ +
+

The pong function accepts one channel for receives +(pings) and a second for sends (pongs).

+ +
+
func pong(pings <-chan string, pongs chan<- string) {
+    msg := <-pings
+    pongs <- msg
+}
+
+ +
+ + +
func main() {
+    pings := make(chan string, 1)
+    pongs := make(chan string, 1)
+    ping(pings, "passed message")
+    pong(pings, pongs)
+    fmt.Println(<-pongs)
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run channel-directions.go
+passed message
+
+ +
+ + +

+ Next example: Select. +

+ + +
+ + diff --git a/public/channel-synchronization b/public/channel-synchronization new file mode 100644 index 0000000..55f85b8 --- /dev/null +++ b/public/channel-synchronization @@ -0,0 +1,170 @@ + + + + + Go by Example: Channel Synchronization + + + + +
+

Go by Example: Channel Synchronization

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

We can use channels to synchronize execution +across goroutines. Here’s an example of using a +blocking receive to wait for a goroutine to finish.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+

This is the function we’ll run in a goroutine. The +done channel will be used to notify another +goroutine that this function’s work is done.

+ +
+
func worker(done chan bool) {
+    fmt.Print("working...")
+    time.Sleep(time.Second)
+    fmt.Println("done")
+
+ +
+

Send a value to notify that we’re done.

+ +
+
    done <- true
+}
+
+ +
+ + +
func main() {
+
+ +
+

Start a worker goroutine, giving it the channel to +notify on.

+ +
+
    done := make(chan bool, 1)
+    go worker(done)
+
+ +
+

Block until we receive a notification from the +worker on the channel.

+ +
+
    <-done
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run channel-synchronization.go      
+working...done                  
+
+ +
+

If you removed the <- done line from this program, the +program would exit before the worker even +started.

+ +
+ +
+ + +

+ Next example: Channel Directions. +

+ + +
+ + diff --git a/public/channels b/public/channels new file mode 100644 index 0000000..799189d --- /dev/null +++ b/public/channels @@ -0,0 +1,160 @@ + + + + + Go by Example: Channels + + + + +
+

Go by Example: Channels

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Channels are the pipes that connect concurrent +goroutines. You can send values into channels from one +goroutine and receive those values into another +goroutine. Channels are a powerful primitive that +underly much of Go’s functionality.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Create a new channel with make(chan val-type). +Channels are typed by the values they convey.

+ +
+
    messages := make(chan string)
+
+ +
+

Send a value into a channel using the channel <- +syntax. Here we send "ping" to the messages +channel we made above, from a new goroutine.

+ +
+
    go func() { messages <- "ping" }()
+
+ +
+

The <-channel syntax receives a value from the +channel. Here we’ll receive the "ping" message +we sent above and print it out.

+ +
+
    msg := <-messages
+    fmt.Println(msg)
+}
+
+ +
+ + + + + + + + + + + + + +
+

When we run the program the "ping" message is +succesfully passed from one goroutine to another via our +channel.

+ +
+
$ go run channels.go 
+ping
+
+ +
+

By default sends and receives block until both the +sender and receiver are ready. This property allowed +us to wait at the end of our program for the "ping" +message without having to use any other synchronization.

+ +
+ +
+ + +

+ Next example: Channel Buffering. +

+ + +
+ + diff --git a/public/closing-channels b/public/closing-channels new file mode 100644 index 0000000..46544e6 --- /dev/null +++ b/public/closing-channels @@ -0,0 +1,185 @@ + + + + + Go by Example: Closing Channels + + + + +
+

Go by Example: Closing Channels

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Closing a channel indicates that no more values +will be sent on it. This can be useful to communicate +completion to the channel’s receivers.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

In this example we’ll use a jobs channel to +communicate work to be done from the main() goroutine +to a worker goroutine. When we have no more jobs for +the worker we’ll close the jobs channel.

+ +
+
func main() {
+    jobs := make(chan int, 5)
+    done := make(chan bool)
+
+ +
+

Here’s the worker goroutine. It repeatedly receives +from jobs with j, more := <-jobs. In this +special 2-value form of receive, the more value +will be false if jobs has been closed and all +values in the channel have already been received. +We use this to notify on done when we’ve worked +all our jobs.

+ +
+
    go func() {
+        for {
+            j, more := <-jobs
+            if more {
+                fmt.Println("received job", j)
+            } else {
+                fmt.Println("received all jobs")
+                done <- true
+                return
+            }
+        }
+    }()
+
+ +
+

This sends 3 jobs to the worker over the jobs +channel, then closes it.

+ +
+
    for j := 1; j <= 3; j++ {
+        jobs <- j
+        fmt.Println("sent job", j)
+    }
+    close(jobs)
+    fmt.Println("sent all jobs")
+
+ +
+

We await the worker using the +synchronization approach +we saw earlier.

+ +
+
    <-done
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run closing-channels.go 
+sent job 1
+received job 1
+sent job 2
+received job 2
+sent job 3
+received job 3
+sent all jobs
+received all jobs
+
+ +
+

The idea of closed channels leads naturally to our next +example: range over channels.

+ +
+ +
+ + +

+ Next example: Range over Channels. +

+ + +
+ + diff --git a/public/closures b/public/closures new file mode 100644 index 0000000..e38208a --- /dev/null +++ b/public/closures @@ -0,0 +1,180 @@ + + + + + Go by Example: Closures + + + + +
+

Go by Example: Closures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports anonymous functions, +which can form closures. +Anonymous functions are useful when you want to define +a function inline without having to name it.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

This function intSeq returns another function, which +we define anonymously in the body of intSeq. The +returned function closes over the variable i to +form a closure.

+ +
+
func intSeq() func() int {
+    i := 0
+    return func() int {
+        i += 1
+        return i
+    }
+}
+
+ +
+ + +
func main() {
+
+ +
+

We call intSeq, assigning the result (a function) +to nextInt. This function value captures its +own i value, which will be updated each time +we call nextInt.

+ +
+
    nextInt := intSeq()
+
+ +
+

See the effect of the closure by calling nextInt +a few times.

+ +
+
    fmt.Println(nextInt())
+    fmt.Println(nextInt())
+    fmt.Println(nextInt())
+
+ +
+

To confirm that the state is unique to that +particular function, create and test a new one.

+ +
+
    newInts := intSeq()
+    fmt.Println(newInts())
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run closures.go
+1
+2
+3
+1
+
+ +
+

The last feature of functions we’ll look at for now is +recursion.

+ +
+ +
+ + +

+ Next example: Recursion. +

+ + +
+ + diff --git a/public/collection-functions b/public/collection-functions new file mode 100644 index 0000000..0813854 --- /dev/null +++ b/public/collection-functions @@ -0,0 +1,348 @@ + + + + + Go by Example: Collection Functions + + + + +
+

Go by Example: Collection Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

We often need our programs to perform operations on +collections of data, like selecting all items that +satisfy a given predicate or mapping all items to a new +collection with a custom function.

+ +
+ +
+

In some languages it’s idiomatic to use generic +data structures and algorithms. Go does not support +generics; in Go it’s common to provide collection +functions if and when they are specifically needed for +your program and data types.

+ +
+ +
+

Here are some example collection functions for slices +of strings. You can use these examples to build your +own functions. Note that in some cases it may be +clearest to just inline the collection-manipulating +code directly, instead of creating and calling a +helper function.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "strings"
+import "fmt"
+
+ +
+

Returns the first index of the target string t, or +-1 if no match is found.

+ +
+
func Index(vs []string, t string) int {
+    for i, v := range vs {
+        if v == t {
+            return i
+        }
+    }
+    return -1
+}
+
+ +
+

Returns true if the target string t is in the +slice.

+ +
+
func Include(vs []string, t string) bool {
+    return Index(vs, t) >= 0
+}
+
+ +
+

Returns true if one of the strings in the slice +satisfies the predicate f.

+ +
+
func Any(vs []string, f func(string) bool) bool {
+    for _, v := range vs {
+        if f(v) {
+            return true
+        }
+    }
+    return false
+}
+
+ +
+

Returns true if all of the strings in the slice +satisfy the predicate f.

+ +
+
func All(vs []string, f func(string) bool) bool {
+    for _, v := range vs {
+        if !f(v) {
+            return false
+        }
+    }
+    return true
+}
+
+ +
+

Returns a new slice containing all strings in the +slice that satisfy the predicate f.

+ +
+
func Filter(vs []string, f func(string) bool) []string {
+    vsf := make([]string, 0)
+    for _, v := range vs {
+        if f(v) {
+            vsf = append(vsf, v)
+        }
+    }
+    return vsf
+}
+
+ +
+

Returns a new slice containing the results of applying +the function f to each string in the original slice.

+ +
+
func Map(vs []string, f func(string) string) []string {
+    vsm := make([]string, len(vs))
+    for i, v := range vs {
+        vsm[i] = f(v)
+    }
+    return vsm
+}
+
+ +
+ + +
func main() {
+
+ +
+

Here we try out our various collection functions.

+ +
+
    var strs = []string{"peach", "apple", "pear", "plum"}
+
+ +
+ + +
    fmt.Println(Index(strs, "pear"))
+
+ +
+ + +
    fmt.Println(Include(strs, "grape"))
+
+ +
+ + +
    fmt.Println(Any(strs, func(v string) bool {
+        return strings.HasPrefix(v, "p")
+    }))
+
+ +
+ + +
    fmt.Println(All(strs, func(v string) bool {
+        return strings.HasPrefix(v, "p")
+    }))
+
+ +
+ + +
    fmt.Println(Filter(strs, func(v string) bool {
+        return strings.Contains(v, "e")
+    }))
+
+ +
+

The above examples all used anonymous functions, +but you can also use named functions of the correct +type.

+ +
+
    fmt.Println(Map(strs, strings.ToUpper))
+
+ +
+ + +
}
+
+ +
+ + + + + + + + +
+ + +
$ go run collection-functions.go 
+2
+false
+true
+false
+[peach apple pear]
+[PEACH APPLE PEAR PLUM]
+
+ +
+ + +

+ Next example: String Functions. +

+ + +
+ + diff --git a/public/command-line-arguments b/public/command-line-arguments new file mode 100644 index 0000000..327c6d6 --- /dev/null +++ b/public/command-line-arguments @@ -0,0 +1,159 @@ + + + + + Go by Example: Command-Line Arguments + + + + +
+

Go by Example: Command-Line Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Command-line arguments +are a common way to parameterize execution of programs. +For example, go run hello.go uses run and +hello.go arguments to the go program.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "os"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

os.Args provides access to raw command-line +arguments. Note that the first value in this slice +is the path to the program, and os.Args[1:] +holds the arguments to the program.

+ +
+
    argsWithProg := os.Args
+    argsWithoutProg := os.Args[1:]
+
+ +
+

You can get individual args with normal indexing.

+ +
+
    arg := os.Args[3]
+
+ +
+ + +
    fmt.Println(argsWithProg)
+    fmt.Println(argsWithoutProg)
+    fmt.Println(arg)
+}
+
+ +
+ + + + + + + + + + + + + +
+

To experiment with command-line arguments it’s best to +build a binary with go build first.

+ +
+
$ go build command-line-arguments.go
+$ ./command-line-arguments a b c d
+[./command-line-arguments a b c d]       
+[a b c d]
+c
+
+ +
+

Next we’ll look at more advanced command-line processing +with flags.

+ +
+ +
+ + +

+ Next example: Command-Line Flags. +

+ + +
+ + diff --git a/public/command-line-flags b/public/command-line-flags new file mode 100644 index 0000000..e2e7e62 --- /dev/null +++ b/public/command-line-flags @@ -0,0 +1,303 @@ + + + + + Go by Example: Command-Line Flags + + + + +
+

Go by Example: Command-Line Flags

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Command-line flags +are a common way to specify options for command-line +programs. For example, in wc -l the -l is a +command-line flag.

+ +
+ +
+ + +
package main
+
+ +
+

Go provides a flag package supporting basic +command-line flag parsing. We’ll use this package to +implement our example command-line program.

+ +
+
import "flag"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Basic flag declarations are available for string, +integer, and boolean options. Here we declare a +string flag word with a default value "foo" +and a short description. This flag.String function +returns a string pointer (not a string value); +we’ll see how to use this pointer below.

+ +
+
    wordPtr := flag.String("word", "foo", "a string")
+
+ +
+

This declares numb and fork flags, using a +similar approach to the word flag.

+ +
+
    numbPtr := flag.Int("numb", 42, "an int")
+    boolPtr := flag.Bool("fork", false, "a bool")
+
+ +
+

It’s also possible to declare an option that uses an +existing var declared elsewhere in the program. +Note that we need to pass in a pointer to the flag +declaration function.

+ +
+
    var svar string
+    flag.StringVar(&svar, "svar", "bar", "a string var")
+
+ +
+

Once all flags are declared, call flag.Parse() +to execute the command-line parsing.

+ +
+
    flag.Parse()
+
+ +
+

Here we’ll just dump out the parsed options and +any trailing positional arguments. Note that we +need to dereference the points with e.g. *wordPtr +to get the actual option values.

+ +
+
    fmt.Println("word:", *wordPtr)
+    fmt.Println("numb:", *numbPtr)
+    fmt.Println("fork:", *boolPtr)
+    fmt.Println("svar:", svar)
+    fmt.Println("tail:", flag.Args())
+}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

To experiment with the command-line flags program it’s +best to first compile it and then run the resulting +binary directly.

+ +
+
$ go build command-line-flags.go
+
+ +
+

Try out the built program by first giving it values for +all flags.

+ +
+
$ ./command-line-flags -word=opt -numb=7 -fork -svar=flag
+word: opt
+numb: 7
+fork: true
+svar: flag
+tail: []
+
+ +
+

Note that if you omit flags they automatically take +their default values.

+ +
+
$ ./command-line-flags -word=opt
+word: opt
+numb: 42
+fork: false
+svar: bar
+tail: []
+
+ +
+

Trailing positional arguments can be provided after +any flags.

+ +
+
$ ./command-line-flags -word=opt a1 a2 a3
+word: opt
+...
+tail: [a1 a2 a3]
+
+ +
+

Note that the flag package requires all flags to +appear before positional arguments (otherwise the flags +will be interpreted as positional arguments).

+ +
+
$ ./command-line-flags -word=opt a1 a2 a3 -num=7
+word: opt
+numb: 42
+fork: false
+svar: bar
+trailing: [a1 a2 a3 -num=7]
+
+ +
+

Use -h or --help flags to get automatically +generated help text for the command-line program.

+ +
+
$ ./command-line-flags -h
+Usage of ./command-line-flags:
+  -fork=false: a bool
+  -numb=42: an int
+  -svar="bar": a string var
+  -word="foo": a string
+
+ +
+

If you provide a flag that wasn’t specified to the +flag package, the program will print an error message +an show the help text again.

+ +
+
$ ./command-line-flags -wat
+flag provided but not defined: -wat
+Usage of ./command-line-flags:
+...
+
+ +
+

Next we’ll look at environment variables, another common +way to parameterize programs.

+ +
+ +
+ + +

+ Next example: Environment Variables. +

+ + +
+ + diff --git a/public/constants b/public/constants new file mode 100644 index 0000000..813eb93 --- /dev/null +++ b/public/constants @@ -0,0 +1,171 @@ + + + + + Go by Example: Constants + + + + +
+

Go by Example: Constants

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports constants of character, string, boolean, +and numeric values.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "math"
+
+ +
+

const declares a constant value.

+ +
+
const s string = "constant"
+
+ +
+ + +
func main() {
+    fmt.Println(s)
+
+ +
+

A const statement can appear anywhere a var +statement can.

+ +
+
    const n = 500000000
+
+ +
+

Constant expressions perform arithmetic with +arbitrary precision.

+ +
+
    const d = 3e20 / n
+    fmt.Println(d)
+
+ +
+

A numeric constant has no type until it’s given +one, such as by an explicit cast.

+ +
+
    fmt.Println(int64(d))
+
+ +
+

A number can be given a type by using it in a +context that requires one, such as a variable +assignment or function call. For example, here +math.Sin expects a float64.

+ +
+
    fmt.Println(math.Sin(n))
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run constant.go 
+constant
+6e+11
+600000000000
+-0.28470407323754404
+
+ +
+ + +

+ Next example: For. +

+ + +
+ + diff --git a/public/defer b/public/defer new file mode 100644 index 0000000..4a978c7 --- /dev/null +++ b/public/defer @@ -0,0 +1,183 @@ + + + + + Go by Example: Defer + + + + +
+

Go by Example: Defer

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Defer is used to ensure that a function call is +performed later in a program’s execution, usually for +purposes of cleanup. defer is often used where e.g. +ensure and finally would be used in other languages.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "os"
+
+ +
+

Suppose we wanted to create a file, write to it, +and then close when we’re done. Here’s how we could +do that with defer.

+ +
+
func main() {
+
+ +
+

Immediately after getting a file object with +createFile, we defer the closing of that file +with closeFile. This will be executed at the end +of the enclosing function (main), after +writeFile has finished.

+ +
+
    f := createFile("/tmp/defer.txt")
+    defer closeFile(f)
+    writeFile(f)
+}
+
+ +
+ + +
func createFile(p string) *os.File {
+    fmt.Println("creating")
+    f, err := os.Create(p)
+    if err != nil {
+        panic(err)
+    }
+    return f
+}
+
+ +
+ + +
func writeFile(f *os.File) {
+    fmt.Println("writing")
+    fmt.Fprintln(f, "data")
+
+ +
+ + +
}
+
+ +
+ + +
func closeFile(f *os.File) {
+    fmt.Println("closing")
+    f.Close()
+}
+
+ +
+ + + + + + + + +
+

Running the program confirms that the file is closed +after being written.

+ +
+
$ go run defer.go
+creating
+writing
+closing
+
+ +
+ + +

+ Next example: Collection Functions. +

+ + +
+ + diff --git a/public/environment-variables b/public/environment-variables new file mode 100644 index 0000000..42c364f --- /dev/null +++ b/public/environment-variables @@ -0,0 +1,175 @@ + + + + + Go by Example: Environment Variables + + + + +
+

Go by Example: Environment Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Environment variables +are a universal mechanism for conveying configuration +information to Unix programs. +Let’s look at how to set, get, and list environment variables.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "os"
+import "strings"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

To set a key/value pair, use os.Setenv. To get a +value for a key, use os.Getenv. This will return +an empty string if the key isn’t present in the +environment.

+ +
+
    os.Setenv("FOO", "1")
+    fmt.Println("FOO:", os.Getenv("FOO"))
+    fmt.Println("BAR:", os.Getenv("BAR"))
+
+ +
+

Use os.Environ to list all key/value pairs in the +environment. This returns a slice of strings in the +form KEY=value. You can strings.Split them to +get the key and value. Here we print all the keys.

+ +
+
    fmt.Println()
+    for _, e := range os.Environ() {
+        pair := strings.Split(e, "=")
+        fmt.Println(pair[0])
+    }
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Running the program shows that we pick up the value +value for FOO that we set in the program, but that +BAR is empty.

+ +
+
$ go run environment-variables.go
+FOO: 1
+BAR: 
+
+ +
+

The list of keys in the environment will depend on your +particular machine.

+ +
+
TERM_PROGRAM
+PATH
+SHELL
+...
+
+ +
+

If we set BAR in the environemnt first, the running +program picks that value up.

+ +
+
$ BAR=2 go run environment-variables.go
+FOO: 1
+BAR: 2
+...
+
+ +
+ + +

+ Next example: Spawning Processes. +

+ + +
+ + diff --git a/public/epoch b/public/epoch new file mode 100644 index 0000000..1d372b3 --- /dev/null +++ b/public/epoch @@ -0,0 +1,166 @@ + + + + + Go by Example: Epoch + + + + +
+

Go by Example: Epoch

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

A common requirement in programs is getting the number +of seconds, milliseconds, or nanoseconds since the +Unix epoch. +Here’s how to do it in Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+ + +
func main() {
+
+ +
+

Use time.Now with Unix or UnixNano to get +elapsed time since the Unix epoch in seconds or +nanoseconds, respectively.

+ +
+
    now := time.Now()
+    secs := now.Unix()
+    nanos := now.UnixNano()
+    fmt.Println(now)
+
+ +
+

Note that there is no UnixMillis, so to get the +milliseconds since epoch you’ll need to manually +dive from nanoseconds.

+ +
+
    millis := nanos / 1000000
+    fmt.Println(secs)
+    fmt.Println(millis)
+    fmt.Println(nanos)
+
+ +
+

You can also convert integer seconds or nanoseconds +since the epoch into the corresponding time.

+ +
+
    fmt.Println(time.Unix(secs, 0))
+    fmt.Println(time.Unix(0, nanos))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run epoch.go 
+2012-10-31 16:13:58.292387 +0000 UTC
+1351700038
+1351700038292
+1351700038292387000
+2012-10-31 16:13:58 +0000 UTC
+2012-10-31 16:13:58.292387 +0000 UTC
+
+ +
+

Next we’ll look at another time-related task: time +parsing and formatting.

+ +
+ +
+ + +

+ Next example: Time Formatting / Parsing. +

+ + +
+ + diff --git a/public/errors b/public/errors new file mode 100644 index 0000000..913656c --- /dev/null +++ b/public/errors @@ -0,0 +1,281 @@ + + + + + Go by Example: Errors + + + + +
+

Go by Example: Errors

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In Go it’s idiomatic to communicate errors via an +explicit, separate return value. This contrasts with +the exceptions used in languages like Java and Ruby and +the overloaded single result / error value sometimes +used in C. Go’s approach makes it easy to see which +functions return errors and to handle them using the +same language constructs employed for any other, +non-error tasks.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "errors"
+import "fmt"
+
+ +
+

By convention, errors are the last return value and +have type error, a built-in interface.

+ +
+
func f1(arg int) (int, error) {
+    if arg == 42 {
+
+ +
+

errors.New constructs a basic error value +with the given error message.

+ +
+
        return -1, errors.New("can't work with 42")
+
+ +
+ + +
    }
+
+ +
+

A nil value in the error position indicates that +there was no error.

+ +
+
    return arg + 3, nil
+}
+
+ +
+

It’s possible to use custom types as errors by +implementing the Error() method on them. Here’s a +variant on the example above that uses a custom type +to explicitly represent an argument error.

+ +
+
type argError struct {
+    arg  int
+    prob string
+}
+
+ +
+ + +
func (e *argError) Error() string {
+    return fmt.Sprintf("%d - %s", e.arg, e.prob)
+}
+
+ +
+ + +
func f2(arg int) (int, error) {
+    if arg == 42 {
+
+ +
+

In this case we use &argError syntax to build +a new struct, supplying values for the two +fields arg and prob.

+ +
+
        return -1, &argError{arg, "can't work with it"}
+    }
+    return arg + 3, nil
+}
+
+ +
+ + +
func main() {
+
+ +
+

The two loops below test out each of our +error-returning functions. Note that the use of an +inline error check on the if line is a common +idiom in Go code.

+ +
+
    for _, i := range []int{7, 42} {
+        if r, e := f1(i); e != nil {
+            fmt.Println("f1 failed:", e)
+        } else {
+            fmt.Println("f1 worked:", r)
+        }
+    }
+    for _, i := range []int{7, 42} {
+        if r, e := f2(i); e != nil {
+            fmt.Println("f2 failed:", e)
+        } else {
+            fmt.Println("f2 worked:", r)
+        }
+    }
+
+ +
+

If you want to programmatically use the data in +a custom error, you’ll need to get the error as an +instance of the custom error type via type +assertion.

+ +
+
    _, e := f2(42)
+    if ae, ok := e.(*argError); ok {
+        fmt.Println(ae.arg)
+        fmt.Println(ae.prob)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run errors.go
+f1 worked: 10
+f1 failed: can't work with 42
+f2 worked: 10
+f2 failed: 42 - can't work with it
+42
+can't work with it
+
+ +
+

See this great post +on the Go blog for more on error handling.

+ +
+ +
+ + +

+ Next example: Goroutines. +

+ + +
+ + diff --git a/public/execing-processes b/public/execing-processes new file mode 100644 index 0000000..8129c91 --- /dev/null +++ b/public/execing-processes @@ -0,0 +1,190 @@ + + + + + Go by Example: Exec'ing Processes + + + + +
+

Go by Example: Exec'ing Processes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In the previous example we looked at +spawning external processes. We +do this when we need an external process accessible to +a running Go process. Sometimes we just want to +completely replace the current Go process with another +(perhaps non-Go) one. To do this we’ll use Go’s +implementation of the classic +exec +function.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "syscall"
+import "os"
+import "os/exec"
+
+ +
+ + +
func main() {
+
+ +
+

For our example we’ll exec ls. Go requires an +abolute path to the binary we want to execute, so +we’ll use exec.LookPath to find it (probably +/bin/ls).

+ +
+
    binary, lookErr := exec.LookPath("ls")
+    if lookErr != nil {
+        panic(lookErr)
+    }
+
+ +
+

Exec requires arguments in slice form (as +apposed to one big string). We’ll give ls a few +common arguments.

+ +
+
    args := []string{"-a", "-l", "-h"}
+
+ +
+

Exec also needs a set of environment variables +to use. Here we just provide our current +environment.

+ +
+
    env := os.Environ()
+
+ +
+

Here’s the actual os.Exec call. If this call is +succesful, the execution of our process will end +here and be replaced by the /bin/ls -a -l -h +process. If there is an error we’ll get a return +value.

+ +
+
    execErr := syscall.Exec(binary, args, env)
+    if execErr != nil {
+        panic(execErr)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

When we run our program it is replaced by ls.

+ +
+
$ go run execing-processes.go
+total 16
+drwxr-xr-x  4 mark 136B Oct 3 16:29 .
+drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
+-rw-r--r--  1 mark 1.3K Oct 3 16:28 execing-processes.go
+
+ +
+

Note that Go does not offer a classic Unix fork +function. Usually this isn’t an issue though, since +starting goroutines, spawning processes, and exec’ing +processes covers most use cases for fork.

+ +
+ +
+ + +

+ Next example: Signals. +

+ + +
+ + diff --git a/public/exit b/public/exit new file mode 100644 index 0000000..a0bc797 --- /dev/null +++ b/public/exit @@ -0,0 +1,162 @@ + + + + + Go by Example: Exit + + + + +
+

Go by Example: Exit

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Use os.Exit to immediately exit with a given +status.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "os"
+
+ +
+ + +
func main() {
+
+ +
+

defers will not be run when using os.Exit, so +this fmt.Println will never be called.

+ +
+
    defer fmt.Println("!")
+
+ +
+

Exit with status 3.

+ +
+
    os.Exit(3)
+}
+
+ +
+

Note that unlike e.g. C, Go does not use an integer +return value from main to indicate exit status. If +you’d like to exit with a non-zero status you should +use os.Exit.

+ +
+ +
+ + + + + + + + + + + + + + + + + + +
+

If you run exit.go using go run, the exit +will be picked up by go and printed.

+ +
+
$ go run exit.go
+exit status 3
+
+ +
+

By building and executing a binary you can see +the status in the terminal.

+ +
+
$ go build exit.go
+$ ./exit
+$ echo $?
+3
+
+ +
+

Note that the ! from our program never got printed.

+ +
+ +
+ + + +
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..d659d1e Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/for b/public/for new file mode 100644 index 0000000..32adec9 --- /dev/null +++ b/public/for @@ -0,0 +1,164 @@ + + + + + Go by Example: For + + + + +
+

Go by Example: For

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

for is Go’s only looping construct. Here are +three basic types of for loops.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

The most basic type, with a single condition.

+ +
+
    i := 1
+    for i <= 3 {
+        fmt.Println(i)
+        i = i + 1
+    }
+
+ +
+

A classic initial/condition/after for loop.

+ +
+
    for j := 7; j <= 9; j++ {
+        fmt.Println(j)
+    }
+
+ +
+

for without a condition will loop repeatedly +until you break out of the loop or return from +the enclosing function.

+ +
+
    for {
+        fmt.Println("loop")
+        break
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run for.go
+1
+2
+3
+7
+8
+9
+loop
+
+ +
+

We’ll see some other for forms latter when we look at +range statements, channels, and other data +structures.

+ +
+ +
+ + +

+ Next example: If/Else. +

+ + +
+ + diff --git a/public/functions b/public/functions new file mode 100644 index 0000000..54c3651 --- /dev/null +++ b/public/functions @@ -0,0 +1,152 @@ + + + + + Go by Example: Functions + + + + +
+

Go by Example: Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Functions are central in Go. We’ll learn about +functions with a few different examples.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

Here’s a function that takes two ints and returns +their sum as an int.

+ +
+
func plus(a int, b int) int {
+
+ +
+

Go requires explicit returns, i.e. it won’t +automatically return the value of the last +expression.

+ +
+
    return a + b
+}
+
+ +
+ + +
func main() {
+
+ +
+

Call a function just as you’d expect, with +name(args).

+ +
+
    res := plus(1, 2)
+    fmt.Println("1+2 =", res)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run functions.go 
+1+2 = 3
+
+ +
+

There are several other features to Go functions. One is +multiple return values, which we’ll look at next.

+ +
+ +
+ + +

+ Next example: Multiple Return Values. +

+ + +
+ + diff --git a/public/goroutines b/public/goroutines new file mode 100644 index 0000000..4fbedf2 --- /dev/null +++ b/public/goroutines @@ -0,0 +1,196 @@ + + + + + Go by Example: Goroutines + + + + +
+

Go by Example: Goroutines

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

A goroutine is a lightweight thread of execution.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func f(from string) {
+    for i := 0; i < 3; i++ {
+        fmt.Println(from, ":", i)
+    }
+}
+
+ +
+ + +
func main() {
+
+ +
+

Suppose we have a function call f(s). Here’s how +we’d call that in the usual way, running it +synchronously.

+ +
+
    f("direct")
+
+ +
+

To invoke this function in a goroutine, use +go f(s). This new goroutine will execute +concurrently with the calling one.

+ +
+
    go f("goroutine")
+
+ +
+

You can also start a goroutine for an anonymous +function call.

+ +
+
    go func(msg string) {
+        fmt.Println(msg)
+    }("going")
+
+ +
+

Our two goroutines are running asynchronously in +separate goroutines now, so execution falls through +to here. This Scanln code requires we press a key +before the program exits.

+ +
+
    var input string
+    fmt.Scanln(&input)
+    fmt.Println("done")
+}
+
+ +
+ + + + + + + + + + + + + +
+

When we run this program, we see the output of the +blocking call first, then the interleaved output of the +two gouroutines. This interleaving reflects the +goroutines being run concurrently by the Go runtime.

+ +
+
$ go run goroutines.go
+direct : 0
+direct : 1
+direct : 2
+goroutine : 0
+going
+goroutine : 1
+goroutine : 2
+<enter>
+done
+
+ +
+

Next we’ll look at a complement to goroutines in +concurrent Go programs: channels.

+ +
+ +
+ + +

+ Next example: Channels. +

+ + +
+ + diff --git a/public/hello-world b/public/hello-world new file mode 100644 index 0000000..88176eb --- /dev/null +++ b/public/hello-world @@ -0,0 +1,132 @@ + + + + + Go by Example: Hello World + + + + +
+

Go by Example: Hello World

+ + + + + + + + + + + + + + + + + + +
+

Our first program will print the classic “hello world” +message. Here’s the full source code.

+ +
+
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+    fmt.Println("hello world")
+}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+

To run the program, put the code in hello-world.go and +use go run.

+ +
+
$ go run hello-world.go
+hello world
+
+ +
+

Sometimes we’ll want to build our programs into +binaries. We can do this using go build.

+ +
+
$ go build hello-world.go
+$ ls
+hello-world	hello-world.go
+
+ +
+

We can then execute the built binary directly.

+ +
+
$ ./hello-world
+hello world
+
+ +
+

Now that we can run and build basic Go programs, let’s +learn more about the language.

+ +
+ +
+ + +

+ Next example: Values. +

+ + +
+ + diff --git a/public/if-else b/public/if-else new file mode 100644 index 0000000..21f4ac0 --- /dev/null +++ b/public/if-else @@ -0,0 +1,174 @@ + + + + + Go by Example: If/Else + + + + +
+

Go by Example: If/Else

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Branching with if and else in Go is +straight-forward.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Here’s a basic example.

+ +
+
    if 7%2 == 0 {
+        fmt.Println("7 is even")
+    } else {
+        fmt.Println("7 is odd")
+    }
+
+ +
+

You can have an if statement without an else.

+ +
+
    if 8%4 == 0 {
+        fmt.Println("8 is divisible by 4")
+    }
+
+ +
+

A statement can proceed conditionals; any variables +declared in this statement are available in all +branches.

+ +
+
    if num := 9; num < 0 {
+        fmt.Println(num, "is negative")
+    } else if num < 10 {
+        fmt.Println(num, "has 1 digit")
+    } else {
+        fmt.Println(num, "has multiple digits")
+    }
+}
+
+ +
+

Note that you don’t need parentheses around conditions +in Go, but that the brackets are required.

+ +
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run if-else.go 
+7 is odd
+8 is divisible by 4
+9 has 1 digit
+
+ +
+

There is no ternary if +in Go, so you’ll need to use a full if statement even +for basic conditions.

+ +
+ +
+ + +

+ Next example: Switch. +

+ + +
+ + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..62fec7a --- /dev/null +++ b/public/index.html @@ -0,0 +1,174 @@ + + + + + Go by Example + + + + +
+

Go by Example

+

+ Go is an + open source programming language designed for + building simple, fast, and reliable software. +

+ +

+ Go by Example is a hands-on introduction + to Go using annotated example programs. Check out + the first example or + browse the full list below. +

+ + + +
+ + diff --git a/public/interfaces b/public/interfaces new file mode 100644 index 0000000..24a40a7 --- /dev/null +++ b/public/interfaces @@ -0,0 +1,222 @@ + + + + + Go by Example: Interfaces + + + + +
+

Go by Example: Interfaces

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Interfaces are named collections of method +signatures.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "math"
+
+ +
+

Here’s a basic interface for geometric shapes.

+ +
+
type geometry interface {
+    area() float64
+    perim() float64
+}
+
+ +
+

For our example we’ll implement this interface on +square and circle types.

+ +
+
type square struct {
+    width, height float64
+}
+type circle struct {
+    radius float64
+}
+
+ +
+

To implement an interface in Go, we just need to +implement all the methods in the interface. Here we +implement geometry on squares.

+ +
+
func (s square) area() float64 {
+    return s.width * s.height
+}
+func (s square) perim() float64 {
+    return 2*s.width + 2*s.height
+}
+
+ +
+

The implementation for circles.

+ +
+
func (c circle) area() float64 {
+    return math.Pi * c.radius * c.radius
+}
+func (c circle) perim() float64 {
+    return 2 * math.Pi * c.radius
+}
+
+ +
+

If a variable has an interface type, then we can call +methods that are in the named interface. Here’s a +generic measure function taking advantage of this +to work on any geometry.

+ +
+
func measure(g geometry) {
+    fmt.Println(g)
+    fmt.Println(g.area())
+    fmt.Println(g.perim())
+}
+
+ +
+ + +
func main() {
+    s := square{width: 3, height: 4}
+    c := circle{radius: 5}
+
+ +
+

The circle and square struct types both +implement the geometry interface so we can use +instances of +these structs as arguments to measure.

+ +
+
    measure(s)
+    measure(c)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run interfaces.go
+{3 4}
+12
+14
+{5}
+78.53981633974483
+31.41592653589793
+
+ +
+

To learn more about Go’s interfaces, check out this +great blog post.

+ +
+ +
+ + +

+ Next example: Errors. +

+ + +
+ + diff --git a/public/json b/public/json new file mode 100644 index 0000000..43bfa4d --- /dev/null +++ b/public/json @@ -0,0 +1,379 @@ + + + + + Go by Example: JSON + + + + +
+

Go by Example: JSON

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go offers built-in support for JSON encoding and +decoding, including to and from built-in and custom +data types.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "encoding/json"
+import "fmt"
+import "os"
+
+ +
+

We’ll use these two structs to demonstrate encoding and +decoding of custom types below.

+ +
+
type Response1 struct {
+    Page   int
+    Fruits []string
+}
+type Response2 struct {
+    Page   int      `json:"page"`
+    Fruits []string `json:"fruits"`
+}
+
+ +
+ + +
func main() {
+
+ +
+

First we’ll look at encoding basic data types to +JSON strings. Here are some examples for atomic +values.

+ +
+
    bolB, _ := json.Marshal(true)
+    fmt.Println(string(bolB))
+
+ +
+ + +
    intB, _ := json.Marshal(1)
+    fmt.Println(string(intB))
+
+ +
+ + +
    fltB, _ := json.Marshal(2.34)
+    fmt.Println(string(fltB))
+
+ +
+ + +
    strB, _ := json.Marshal("gopher")
+    fmt.Println(string(strB))
+
+ +
+

And here are some for slices and maps, which encode +to JSON arrays and objects as you’d expect.

+ +
+
    slcD := []string{"apple", "peach", "pear"}
+    slcB, _ := json.Marshal(slcD)
+    fmt.Println(string(slcB))
+
+ +
+ + +
    mapD := map[string]int{"apple": 5, "lettuce": 7}
+    mapB, _ := json.Marshal(mapD)
+    fmt.Println(string(mapB))
+
+ +
+

The JSON package can automatically encode your +custom data types. It will only include exported +fields in the encoded output and will by default +use those names as the JSON keys.

+ +
+
    res1D := &Response1{
+        Page:   1,
+        Fruits: []string{"apple", "peach", "pear"}}
+    res1B, _ := json.Marshal(res1D)
+    fmt.Println(string(res1B))
+
+ +
+

You can use tags on struct field declarations +to customize the encoded JSON key names. Check the +definition of Response2 above to see an example +of such tags.

+ +
+
    res2D := &Response2{
+        Page:   1,
+        Fruits: []string{"apple", "peach", "pear"}}
+    res2B, _ := json.Marshal(res2D)
+    fmt.Println(string(res2B))
+
+ +
+

Now let’s look at decoding JSON data into Go +values. Here’s an example for a generic data +structure.

+ +
+
    byt := []byte(`{"num":6.0,"strs":["a","b"]}`)
+
+ +
+

We need to provide a variable where the JSON +package can put the decoded data. This +map[string]interface{} will hold a map of strings +to arbitrary data types.

+ +
+
    var dat map[string]interface{}
+
+ +
+

Here’s the actual decoding, and a check for +associated errors.

+ +
+
    if err := json.Unmarshal(byt, &dat); err != nil {
+        panic(err)
+    }
+    fmt.Println(dat)
+
+ +
+

In order to use the values in the decoded map, +we’ll need to cast them to their appropriate type. +For example here we cast the value in num to +the expected float64 type.

+ +
+
    num := dat["num"].(float64)
+    fmt.Println(num)
+
+ +
+

Accessing nested data requires a series of +casts.

+ +
+
    strs := dat["strs"].([]interface{})
+    str1 := strs[0].(string)
+    fmt.Println(str1)
+
+ +
+

We can also decode JSON into custom data types. +This has the advantages of adding additional +type-safety to our programs and eliminating the +need for type assertions when accessing the decoded +data.

+ +
+
    str := `{"page": 1, "fruits": ["apple", "peach"]}`
+    res := &Response2{}
+    json.Unmarshal([]byte(str), &res)
+    fmt.Println(res)
+    fmt.Println(res.Fruits[0])
+
+ +
+

In the examples above we always used bytes and +strings as intermediates between the data and +JSON representation on standard out. We can also +stream JSON encodings directly to os.Writers like +os.Stdout or even HTTP response bodies.

+ +
+
    enc := json.NewEncoder(os.Stdout)
+    d := map[string]int{"apple": 5, "lettuce": 7}
+    enc.Encode(d)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run json.go
+true
+1
+2.34
+"gopher"
+["apple","peach","pear"]
+{"apple":5,"lettuce":7}
+{"Page":1,"Fruits":["apple","peach","pear"]}
+{"page":1,"fruits":["apple","peach","pear"]}
+map[num:6 strs:[a b]]
+6
+a
+&{1 [apple peach]}
+apple
+{"apple":5,"lettuce":7}
+
+ +
+

We’ve covered the basic of JSON in Go here, but check +out the JSON and Go +blog post and JSON package docs +for more.

+ +
+ +
+ + +

+ Next example: Time. +

+ + +
+ + diff --git a/public/line-filters b/public/line-filters new file mode 100644 index 0000000..a8a00d8 --- /dev/null +++ b/public/line-filters @@ -0,0 +1,207 @@ + + + + + Go by Example: Line Filters + + + + +
+

Go by Example: Line Filters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

A line filter is a common type of program that reads +input on stdin, processes it, and then prints some +derived result to stdout. grep and sed are common +line filters.

+ +
+ +
+

Here’s an example line filter in Go that writes a +capitalized version of all input text. You can use this +pattern to write your own Go line filters.

+ +
+
package main
+
+ +
+ + +
import (
+    "bufio"
+    "fmt"
+    "io"
+    "os"
+    "strings"
+)
+
+ +
+ + +
func main() {
+
+ +
+

Wrapping the unbuffered os.Stdin with a buffered +reader gives us a convenient ReadString method +that we’ll use to read input line-by-line.

+ +
+
    rdr := bufio.NewReader(os.Stdin)
+    out := os.Stdout
+
+ +
+

ReadString returns the next string from the +input up to the given separator byte. We give the +newline byte '\n' as our separator so we’ll get +successive input lines.

+ +
+
    for {
+        switch line, err := rdr.ReadString('\n'); err {
+
+ +
+

If the read succeeded (the read err is nil), +write out out the uppercased line. Check for an +error on this write as we do on the read.

+ +
+
        case nil:
+            ucl := strings.ToUpper(line)
+            if _, err = out.WriteString(ucl); err != nil {
+                fmt.Fprintln(os.Stderr, "error:", err)
+                os.Exit(1)
+            }
+
+ +
+

The EOF error is expected when we reach the +end of input, so exit gracefully in that case.

+ +
+
        case io.EOF:
+            os.Exit(0)
+
+ +
+

Otherwise there’s a problem; print the +error and exit with non-zero status.

+ +
+
        default:
+            fmt.Fprintln(os.Stderr, "error:", err)
+            os.Exit(1)
+        }
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

To try out our line filter, first make a file with a few +lowercase lines.

+ +
+
$ echo 'hello'   > /tmp/lines
+$ echo 'filter' >> /tmp/lines
+
+ +
+

Then use the line filter to get uppercase lines.

+ +
+
$ cat /tmp/lines | go run line-filters.go
+HELLO
+FILTER
+
+ +
+ + +

+ Next example: Command-Line Arguments. +

+ + +
+ + diff --git a/public/maps b/public/maps new file mode 100644 index 0000000..72d94d7 --- /dev/null +++ b/public/maps @@ -0,0 +1,217 @@ + + + + + Go by Example: Maps + + + + +
+

Go by Example: Maps

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Maps are Go’s built-in associative data type +(sometimes called hashes or dicts in other languages).

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

To create an empty map, use the builtin make: +make(map[key-type]val-type).

+ +
+
    m := make(map[string]int)
+
+ +
+

Set key/value pairs using typical name[key] = val +syntax.

+ +
+
    m["k1"] = 7
+    m["k2"] = 13
+
+ +
+

Printing a map with e.g. Println will show all of +its key/value pairs.

+ +
+
    fmt.Println("map:", m)
+
+ +
+

Get a value for a key with name[key].

+ +
+
    v1 := m["k1"]
+    fmt.Println("v1: ", v1)
+
+ +
+

The builtin len returns the number of key/value +pairs when called on a map.

+ +
+
    fmt.Println("len:", len(m))
+
+ +
+

The builtin delete removes key/value pairs from +a map.

+ +
+
    delete(m, "k2")
+    fmt.Println("map:", m)
+
+ +
+

The optional second return value when getting a +value from a map indiciates if the key was present +in the map. This can be used to disambiguate +between missing keys and keys with zero values +like 0 or "".

+ +
+
    _, prs := m["k2"]
+    fmt.Println("prs:", prs)
+
+ +
+

You can also declare and initialize a new map in +the same line with this syntax.

+ +
+
    n := map[string]int{"foo": 1, "bar": 2}
+    fmt.Println("map:", n)
+}
+
+ +
+ + + + + + + + +
+

Note that maps appear in the form map[k:v k:v] when +printed with fmt.Println.

+ +
+
$ go run maps.go 
+map: map[k1:7 k2:13]
+v1:  7
+len: 2
+map: map[k1:7]
+prs: false
+map: map[foo:1 bar:2]
+
+ +
+ + +

+ Next example: Range. +

+ + +
+ + diff --git a/public/methods b/public/methods new file mode 100644 index 0000000..b618bc1 --- /dev/null +++ b/public/methods @@ -0,0 +1,186 @@ + + + + + Go by Example: Methods + + + + +
+

Go by Example: Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports methods defined on struct types.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
type rect struct {
+    width, height int
+}
+
+ +
+

This area method has a receiver type of *rect.

+ +
+
func (r *rect) area() int {
+    return r.width * r.height
+}
+
+ +
+

Methods can be defined for either pointer or value +receiver types. Here’s an example of a value receiver.

+ +
+
func (r rect) perim() int {
+    return 2*r.width + 2*r.height
+}
+
+ +
+ + +
func main() {
+    r := rect{width: 10, height: 5}
+
+ +
+

Here we call the 2 methods defined for our struct.

+ +
+
    fmt.Println("area: ", r.area())
+    fmt.Println("perim:", r.perim())
+
+ +
+

Go automatically handles conversion between values +and pointers for method calls. You may want to use +a pointer receiver type to avoid copying on method +calls or to allow the method to mutate the +receiving struct.

+ +
+
    rp := &r
+    fmt.Println("area: ", rp.area())
+    fmt.Println("perim:", rp.perim())
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run methods.go 
+area:  50
+perim: 30
+area:  50
+perim: 30
+
+ +
+

Next we’ll look at Go’s mechanism for grouping and +naming related sets of methods: interfaces.

+ +
+ +
+ + +

+ Next example: Interfaces. +

+ + +
+ + diff --git a/public/multiple-return-values b/public/multiple-return-values new file mode 100644 index 0000000..5de0a1f --- /dev/null +++ b/public/multiple-return-values @@ -0,0 +1,157 @@ + + + + + Go by Example: Multiple Return Values + + + + +
+

Go by Example: Multiple Return Values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go has built-in support for multiple return values. +This feature is used often in idiomatic Go, for example +to return both result and error values from a function.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

The (int, int) in this function signature shows that +the function returns 2 ints.

+ +
+
func vals() (int, int) {
+    return 3, 7
+}
+
+ +
+ + +
func main() {
+
+ +
+

Here we use the 2 different return values from the +call with multiple assignment.

+ +
+
    a, b := vals()
+    fmt.Println(a)
+    fmt.Println(b)
+
+ +
+

If you only want a subset of the returned values, +use the blank identifier _.

+ +
+
    _, c := vals()
+    fmt.Println(c)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run multiple-return-values.go
+3
+7
+7
+
+ +
+

Accepting a variable number of arguments is another nice +feature of Go functions; we’ll look at this next.

+ +
+ +
+ + +

+ Next example: Variadic Functions. +

+ + +
+ + diff --git a/public/mutexes b/public/mutexes new file mode 100644 index 0000000..addec28 --- /dev/null +++ b/public/mutexes @@ -0,0 +1,285 @@ + + + + + Go by Example: Mutexes + + + + +
+

Go by Example: Mutexes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In the previous example we saw how to manage simple +counter state using atomic operations. For more complex +state we can use a mutex +to safely access data across multiple goroutines.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import (
+    "fmt"
+    "math/rand"
+    "runtime"
+    "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{}
+
+ +
+

To compare the mutex-based approach with another +we’ll see later, ops will count how many +operations we perform against the state.

+ +
+
    var ops int64 = 0
+
+ +
+

Here we start 100 goroutines to execute repeated +reads against the state.

+ +
+
    for r := 0; r < 100; r++ {
+        go func() {
+            total := 0
+            for {
+
+ +
+

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 ops count.

+ +
+
                key := rand.Intn(5)
+                mutex.Lock()
+                total += state[key]
+                mutex.Unlock()
+                atomic.AddInt64(&ops, 1)
+
+ +
+

In order to ensure that this goroutine +doesn’t starve the scheduler, we explicitly +yield after each operation with +runtime.Gosched(). This yielding is +handled automatically with e.g. every +channel operation and for blocking +calls like time.Sleep, but in this +case we need to do it manually.

+ +
+
                runtime.Gosched()
+            }
+        }()
+    }
+
+ +
+

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.AddInt64(&ops, 1)
+                runtime.Gosched()
+            }
+        }()
+    }
+
+ +
+

Let the 110 goroutines work on the state and +mutex for a second.

+ +
+
    time.Sleep(time.Second)
+
+ +
+

Take and report a final operations count.

+ +
+
    opsFinal := atomic.LoadInt64(&ops)
+    fmt.Println("ops:", opsFinal)
+
+ +
+

With a final lock of state, show how it ended up.

+ +
+
    mutex.Lock()
+    fmt.Println("state:", state)
+    mutex.Unlock()
+}
+
+ +
+ + + + + + + + + + + + + +
+

Running the program shows that we executed about +3,500,000 operations against our mutex-synchronized +state.

+ +
+
$ go run mutexes.go
+ops: 3598302
+state: map[1:38 4:98 2:23 3:85 0:44]
+
+ +
+

Next we’ll look at implementing this same state +management task using only goroutines and channels.

+ +
+ +
+ + +

+ Next example: Stateful Goroutines. +

+ + +
+ + diff --git a/public/non-blocking-channel-operations b/public/non-blocking-channel-operations new file mode 100644 index 0000000..4e5e16c --- /dev/null +++ b/public/non-blocking-channel-operations @@ -0,0 +1,165 @@ + + + + + Go by Example: Non-Blocking Channel Operations + + + + +
+

Go by Example: Non-Blocking Channel Operations

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Basic sends and receives on channels are blocking. +However, we can use select with a default clause to +implement non-blocking sends, receives, and even +non-blocking multi-way selects.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+    messages := make(chan string)
+    signals := make(chan bool)
+
+ +
+

Here’s a non-blocking receive. If a value is +available on messages then select will take +the <-messages case with that value. If not +it will immediately take the default case.

+ +
+
    select {
+    case msg := <-messages:
+        fmt.Println("received message", msg)
+    default:
+        fmt.Println("no message received")
+    }
+
+ +
+

A non-blocking send works similarly.

+ +
+
    msg := "hi"
+    select {
+    case messages <- msg:
+        fmt.Println("sent message", msg)
+    default:
+        fmt.Println("no message sent")
+    }
+
+ +
+

We can use multiple cases above the default +clause to implement a multi-way non-blocking +select. Here we attempt non-blocking receives +on both messages and signals.

+ +
+
    select {
+    case msg := <-messages:
+        fmt.Println("received message", msg)
+    case sig := <-signals:
+        fmt.Println("received signal", sig)
+    default:
+        fmt.Println("no activity")
+    }
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run non-blocking-channel-operations.go 
+no message received
+no message sent
+no activity
+
+ +
+ + +

+ Next example: Closing Channels. +

+ + +
+ + diff --git a/public/number-parsing b/public/number-parsing new file mode 100644 index 0000000..6d92683 --- /dev/null +++ b/public/number-parsing @@ -0,0 +1,199 @@ + + + + + Go by Example: Number Parsing + + + + +
+

Go by Example: Number Parsing

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Parsing numbers from strings is a basic but common task +in many programs; here’s how to do it in Go.

+ +
+ +
+ + +
package main
+
+ +
+

The built-in package strconv provides the number +parsing.

+ +
+
import "strconv"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

With ParseFloat, this 64 tells how many bits of +precision to parse.

+ +
+
    f, _ := strconv.ParseFloat("1.234", 64)
+    fmt.Println(f)
+
+ +
+

For ParseInt, the 0 means infer the base from +the string. 64 requires that the result fit in 64 +bits.

+ +
+
    i, _ := strconv.ParseInt("123", 0, 64)
+    fmt.Println(i)
+
+ +
+

ParseInt will recognize hex-formatted numbers.

+ +
+
    d, _ := strconv.ParseInt("0x1c8", 0, 64)
+    fmt.Println(d)
+
+ +
+

A ParseUint is also available.

+ +
+
    u, _ := strconv.ParseUint("789", 0, 64)
+    fmt.Println(u)
+
+ +
+

Atoi is a convenience function for basic base-10 +int parsing.

+ +
+
    k, _ := strconv.Atoi("135")
+    fmt.Println(k)
+
+ +
+

Parse functions return an error on bad input.

+ +
+
    _, e := strconv.Atoi("wat")
+    fmt.Println(e)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run number-parsing.go 
+1.234
+123
+456
+789
+135
+strconv.ParseInt: parsing "wat": invalid syntax
+
+ +
+

Next we’ll look at another common parsing task: URLs.

+ +
+ +
+ + +

+ Next example: URL Parsing. +

+ + +
+ + diff --git a/public/panic b/public/panic new file mode 100644 index 0000000..95620aa --- /dev/null +++ b/public/panic @@ -0,0 +1,163 @@ + + + + + Go by Example: Panic + + + + +
+

Go by Example: Panic

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

A panic typically means something went unexpectedly +wrong. Mostly we use it to fail fast on errors that +shouldn’t occur during normal operation, or that we +aren’t prepared to handle gracefully.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "os"
+
+ +
+ + +
func main() {
+
+ +
+

We’ll use panic throughout this site to check for +unexpected errors. This is the only program on the +site designed to panic.

+ +
+
    panic("a problem")
+
+ +
+

A common use of panic is to abort if a function +returns an error value that we don’t know how to +(or want to) handle. Here’s an example of +panicking if we get an unexpected error when creating a new file.

+ +
+
    _, err := os.Create("/tmp/file")
+    if err != nil {
+        panic(err)
+    }
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Running this program will cause it to panic, print +an error message and goroutine traces, and exit with +a non-zero status.

+ +
+
$ go run panic.go
+panic: a problem
+
+ +
+ + +
goroutine 1 [running]:
+main.main()
+	/.../panic.go:12 +0x47
+...
+exit status 2
+
+ +
+

Note that unlike some languages which use exceptions +for handling of many errors, in Go it is idiomatic +to use error-indicating return values wherever possible.

+ +
+ +
+ + +

+ Next example: Defer. +

+ + +
+ + diff --git a/public/pointers b/public/pointers new file mode 100644 index 0000000..598dbfd --- /dev/null +++ b/public/pointers @@ -0,0 +1,183 @@ + + + + + Go by Example: Pointers + + + + +
+

Go by Example: Pointers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports pointers, +allowing you to pass references to values and records +within your program.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

We’ll show how pointers work in contrast to values with +2 functions: zeroval and zeroptr. zeroval has an +int parameter, so arguments will be passed to it by +value. zeroval will get a copy of ival distinct +from the one in the calling function.

+ +
+
func zeroval(ival int) {
+    ival = 0
+}
+
+ +
+

zeroptr in contrast has an *int parameter, meaning +that it takes an int pointer. The *iptr code in the +function body then dereferences the pointer from its +memory address to the current value at that address. +Assigning a value to a dereferenced pointer changes the +value at the referenced address.

+ +
+
func zeroptr(iptr *int) {
+    *iptr = 0
+}
+
+ +
+ + +
func main() {
+    i := 1
+    fmt.Println("initial:", i)
+
+ +
+ + +
    zeroval(i)
+    fmt.Println("zeroval:", i)
+
+ +
+

The &i syntax gives the memory address of i, +i.e. a pointer to i.

+ +
+
    zeroptr(&i)
+    fmt.Println("zeroptr:", i)
+
+ +
+

Pointers can be printed too.

+ +
+
    fmt.Println("pointer:", &i)
+}
+
+ +
+ + + + + + + + +
+

zeroval doesn’t change the i in main, but +zeroptr does because it has a reference to +the memory address for that variable.

+ +
+
$ go run pointers.go
+initial: 1
+zeroval: 1
+zeroptr: 0
+pointer: 0x42131100
+
+ +
+ + +

+ Next example: Structs. +

+ + +
+ + diff --git a/public/random-numbers b/public/random-numbers new file mode 100644 index 0000000..384a074 --- /dev/null +++ b/public/random-numbers @@ -0,0 +1,206 @@ + + + + + Go by Example: Random Numbers + + + + +
+

Go by Example: Random Numbers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s math/rand package provides +pseudorandom number +generation.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "math/rand"
+
+ +
+ + +
func main() {
+
+ +
+

For example, rand.Intn returns a random int n, +0 <= n < 100.

+ +
+
    fmt.Print(rand.Intn(100), ",")
+    fmt.Print(rand.Intn(100))
+    fmt.Println()
+
+ +
+

rand.Float64 returns a float64 f, +0.0 <= f < 1.0.

+ +
+
    fmt.Println(rand.Float64())
+
+ +
+

This can be used to generate random floats in +other ranges, for example 5.0 <= f' < 10.0.

+ +
+
    fmt.Print((rand.Float64()*5)+5, ",")
+    fmt.Print((rand.Float64() * 5) + 5)
+    fmt.Println()
+
+ +
+

To make the pseudorandom generator deterministic, +give it a well-known seed.

+ +
+
    s1 := rand.NewSource(42)
+    r1 := rand.New(s1)
+
+ +
+

Call the resulting rand.Source 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)
+    r2 := rand.New(s2)
+    fmt.Print(r2.Intn(100), ",")
+    fmt.Print(r2.Intn(100))
+    fmt.Println()
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run random-numbers.go 
+81,87
+0.6645600532184904
+7.123187485356329,8.434115364335547
+5,87
+5,87
+
+ +
+

See the math/rand +package docs for references on other random quantities +that Go can provide.

+ +
+ +
+ + +

+ Next example: Number Parsing. +

+ + +
+ + diff --git a/public/range b/public/range new file mode 100644 index 0000000..06799fe --- /dev/null +++ b/public/range @@ -0,0 +1,174 @@ + + + + + Go by Example: Range + + + + +
+

Go by Example: Range

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

range iterates over of elements in a variety of +data structures. Let’s see how to use range with some +of the data structures we’ve already learned.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Here we use range to sum the numbers in a slice. +Arrays work like this too.

+ +
+
    nums := []int{2, 3, 4}
+    sum := 0
+    for _, num := range nums {
+        sum += num
+    }
+    fmt.Println("sum:", sum)
+
+ +
+

range on arrays and slices provides both the +index and value for each entry. Above we didn’t +need the index, so we ignored it with the +blank identifier _. Sometimes we actually want +the indexes though.

+ +
+
    for i, num := range nums {
+        if num == 3 {
+            fmt.Println("index:", i)
+        }
+    }
+
+ +
+

range on map iterates over key/value pairs.

+ +
+
    kvs := map[string]string{"a": "apple", "b": "bannana"}
+    for k, v := range kvs {
+        fmt.Printf("%s -> %s\n", k, v)
+    }
+
+ +
+

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.

+ +
+
    for i, c := range "go" {
+        fmt.Println(i, c)
+    }
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run range.go 
+sum: 9
+index: 1
+a -> apple
+b -> bannana
+0 103
+1 111
+
+ +
+ + +

+ Next example: Functions. +

+ + +
+ + diff --git a/public/range-over-channels b/public/range-over-channels new file mode 100644 index 0000000..0690cf4 --- /dev/null +++ b/public/range-over-channels @@ -0,0 +1,147 @@ + + + + + Go by Example: Range over Channels + + + + +
+

Go by Example: Range over Channels

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In a previous 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.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

We’ll iterate over 2 values in the queue channel.

+ +
+
    queue := make(chan string, 2)
+    queue <- "one"
+    queue <- "two"
+    close(queue)
+
+ +
+

This range iterates over each element as it’s +received from queue. Because we closed the +channel above, the iteration terminates after +receiving the 2 elements. If we didn’t close it +we’d block on a 3rd receive in the loop.

+ +
+
    for elem := range queue {
+        fmt.Println(elem)
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run range-over-channels.go
+one
+two
+
+ +
+

This example also showed that it’s possible to close +a non-empty channel but still have the remaining +values be received.

+ +
+ +
+ + +

+ Next example: Timers. +

+ + +
+ + diff --git a/public/rate-limiting b/public/rate-limiting new file mode 100644 index 0000000..cf5a9c6 --- /dev/null +++ b/public/rate-limiting @@ -0,0 +1,246 @@ + + + + + Go by Example: Rate Limiting + + + + +
+

Go by Example: Rate Limiting

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Rate limiting +is an important mechanism for controlling resource +utilization and maintaining quality of service. Go +elegantly supports rate limiting with goroutines, +channels, and tickers.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "time"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

First we’ll look at basic rate limiting. Suppose +we want to limit our handling of incoming requests. +We’ll serve these requests off a channel of the +same name.

+ +
+
    requests := make(chan int, 5)
+    for i := 1; i <= 5; i++ {
+        requests <- i
+    }
+    close(requests)
+
+ +
+

This limiter channel will receive a value +every 200 milliseconds. This is the regulator in +our rate limiting scheme.

+ +
+
    limiter := time.Tick(time.Millisecond * 200)
+
+ +
+

By blocking on a receive from the limiter channel +before serving each request, we limit ourselves to +1 request every 200 milliseconds.

+ +
+
    for req := range requests {
+        <-limiter
+        fmt.Println("request", req, time.Now())
+    }
+
+ +
+

We may want to allow short bursts of requests in +our rate limiting scheme while preserving the +overall rate limit. We can accomplish this by +buffering our limiter channel. This burstyLimiter +channel will allow bursts of up to 3 events.

+ +
+
    burstyLimiter := make(chan time.Time, 3)
+
+ +
+

Fill up the channel to represent allowed bursting.

+ +
+
    for i := 0; i < 3; i++ {
+        burstyLimiter <- time.Now()
+    }
+
+ +
+

Every 200 milliseconds we’ll try to add a new +value to burstyLimiter, up to its limit of 3.

+ +
+
    go func() {
+        for t := range time.Tick(time.Millisecond * 200) {
+            burstyLimiter <- t
+        }
+    }()
+
+ +
+

Now simulate 5 more incoming requests. The first +3 of these will benefit from the burst capability +of burstyLimiter.

+ +
+
    burstyRequests := make(chan int, 5)
+    for i := 1; i <= 5; i++ {
+        burstyRequests <- i
+    }
+    close(burstyRequests)
+    for req := range burstyRequests {
+        <-burstyLimiter
+        fmt.Println("request", req, time.Now())
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Running our program we see the first batch of requests +handled once every ~200 milliseconds as desired.

+ +
+
$ go run rate-limiting.go
+request 1 2012-10-19 00:38:18.687438 +0000 UTC
+request 2 2012-10-19 00:38:18.887471 +0000 UTC
+request 3 2012-10-19 00:38:19.087238 +0000 UTC
+request 4 2012-10-19 00:38:19.287338 +0000 UTC
+request 5 2012-10-19 00:38:19.487331 +0000 UTC
+
+ +
+

For the second batch of requests we serve the first +3 immediately because of the burstable rate limiting, +then serve the remaining 2 with ~200ms delays each.

+ +
+
request 1 2012-10-19 00:38:20.487578 +0000 UTC
+request 2 2012-10-19 00:38:20.487645 +0000 UTC
+request 3 2012-10-19 00:38:20.487676 +0000 UTC
+request 4 2012-10-19 00:38:20.687483 +0000 UTC
+request 5 2012-10-19 00:38:20.887542 +0000 UTC
+
+ +
+ + +

+ Next example: Atomic Counters. +

+ + +
+ + diff --git a/public/reading-files b/public/reading-files new file mode 100644 index 0000000..f3f5562 --- /dev/null +++ b/public/reading-files @@ -0,0 +1,280 @@ + + + + + Go by Example: Reading Files + + + + +
+

Go by Example: Reading Files

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Reading and writing files are basic tasks needed for +many Go programs. First we’ll look at some examples of +reading files.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import (
+    "bufio"
+    "fmt"
+    "io"
+    "io/ioutil"
+    "os"
+)
+
+ +
+

Reading files requires checking most calls for errors. +This helper will streamline our error checks below.

+ +
+
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + +
func main() {
+
+ +
+

Perhaps the most basic file reading task is +slurping a file’s entire contents into memory.

+ +
+
    dat, err := ioutil.ReadFile("/tmp/dat")
+    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 Opening a file to obtain an os.File value.

+ +
+
    f, err := os.Open("/tmp/dat")
+
+ +
+

Read some bytes from the beginning of the file. +Allow up to 5 to be read but also not how many +actually were read.

+ +
+
    b1 := make([]byte, 5)
+    n1, err := f.Read(b1)
+    check(err)
+    fmt.Printf("%d bytes: %s\n", n1, string(b1))
+
+ +
+

You can also Seek to a known location in the file +and Read from there.

+ +
+
    o2, err := f.Seek(6, 0)
+    check(err)
+    b2 := make([]byte, 2)
+    n2, err := f.Read(b2)
+    check(err)
+    fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2))
+
+ +
+

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)
+    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)
+    check(err)
+
+ +
+

The bufio package implements a buffered +reader that may be useful both for it’s efficiency +with many small reads and because of the additional +reading methods it provides.

+ +
+
    r4 := bufio.NewReader(f)
+    b4, err := r4.Peek(5)
+    check(err)
+    fmt.Printf("5 bytes: %s\n", string(b4))
+
+ +
+

Close the file when you’re done (usually this would +be scheduled immediately after Opening with +defer).

+ +
+
    f.Close()
+
+ +
+ + +
}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ echo "hello" > /tmp/dat
+$ echo "go" >>   /tmp/dat
+$ go run reading-files.go 
+hello
+go
+5 bytes: hello
+2 bytes @ 6: go
+2 bytes @ 6: go
+5 bytes: hello
+
+ +
+

Next we’ll look at writing files.

+ +
+ +
+ + +

+ Next example: Writing Files. +

+ + +
+ + diff --git a/public/recursion b/public/recursion new file mode 100644 index 0000000..df21191 --- /dev/null +++ b/public/recursion @@ -0,0 +1,119 @@ + + + + + Go by Example: Recursion + + + + +
+

Go by Example: Recursion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports +recursive functions. +Here’s a classic factorial example.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

This fact function calls itself until it reaches the +base case of fact(0).

+ +
+
func fact(n int) int {
+    if n == 0 {
+        return 1
+    }
+    return n * fact(n-1)
+}
+
+ +
+ + +
func main() {
+    fmt.Println(fact(7))
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run recursion.go 
+5040
+
+ +
+ + +

+ Next example: Pointers. +

+ + +
+ + diff --git a/public/regular-expressions b/public/regular-expressions new file mode 100644 index 0000000..9d82695 --- /dev/null +++ b/public/regular-expressions @@ -0,0 +1,320 @@ + + + + + Go by Example: Regular Expressions + + + + +
+

Go by Example: Regular Expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go offers built-in support for regular expressions. +Here are some examples of common regexp-related tasks +in Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "bytes"
+import "fmt"
+import "regexp"
+
+ +
+ + +
func main() {
+
+ +
+

This tests whether a pattern matches a string.

+ +
+
    match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
+    fmt.Println(match)
+
+ +
+

Above we used a string pattern directly, but for +other regexp tasks you’ll need to Compile an +optimized Regexp struct.

+ +
+
    r, _ := regexp.Compile("p([a-z]+)ch")
+
+ +
+

Many methods are available on these structs. Here’s +a match test like we saw earlier.

+ +
+
    fmt.Println(r.MatchString("peach"))
+
+ +
+

This finds the match for the regexp.

+ +
+
    fmt.Println(r.FindString("peach punch"))
+
+ +
+

The 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"))
+
+ +
+

The Submatch variants include information about +both the whole-pattern matches and the submatches +within those matches. For example this will return +information for both p([a-z]+)ch and ([a-z]+).

+ +
+
    fmt.Println(r.FindStringSubmatch("peach punch"))
+
+ +
+

Similarly this will return information about the +indexes of matches and submatches.

+ +
+
    fmt.Println(r.FindStringSubmatchIndex("peach punch"))
+
+ +
+

The All variants of these functions apply to all +matches in the input, not just the first. For +example to find all matches for a regexp.

+ +
+
    fmt.Println(r.FindAllString("peach punch pinch", -1))
+
+ +
+

These All variants are available for the other +functions we saw above as well.

+ +
+
    fmt.Println(r.FindAllStringSubmatchIndex(
+        "peach punch pinch", -1))
+
+ +
+

Providing a non-negative integer as the second +argument to these functions will limit the number +of matches.

+ +
+
    fmt.Println(r.FindAllString("peach punch pinch", 2))
+
+ +
+

Our examples above had string arguments and used +names like MatchString. We can also provide +[]byte arguments and drop String from the +function name.

+ +
+
    fmt.Println(r.Match([]byte("peach")))
+
+ +
+

When creating constants with regular expressions +you can use the MustCompile variation of +Compile. A plain Compile won’t work for +constants because it has 2 return values.

+ +
+
    r = regexp.MustCompile("p([a-z]+)ch")
+    fmt.Println(r)
+
+ +
+

The regexp package can also be used to replace +subsets of strings with other values.

+ +
+
    fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
+
+ +
+

The Func variant allows you to transform matched +text with a given function.

+ +
+
    in := []byte("a peach")
+    out := r.ReplaceAllFunc(in, bytes.ToUpper)
+    fmt.Println(string(out))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run regular-expressions.go 
+true
+true
+peach
+[0 5]
+[peach ea]
+[0 5 1 3]
+[peach punch pinch]
+[[0 5 1 3] [6 11 7 9] [12 17 13 15]]
+[peach punch]
+true
+p([a-z]+)ch
+a <fruit>
+a PEACH
+
+ +
+

For a complete reference on Go regular expressions check +the regexp package docs.

+ +
+ +
+ + +

+ Next example: JSON. +

+ + +
+ + diff --git a/public/select b/public/select new file mode 100644 index 0000000..de44372 --- /dev/null +++ b/public/select @@ -0,0 +1,172 @@ + + + + + Go by Example: Select + + + + +
+

Go by Example: Select

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s select lets you wait on multiple channel +operations. Combining goroutines and channels with +select is powerful feature of Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "time"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

For our example we’ll select across two channels.

+ +
+
    c1 := make(chan string)
+    c2 := make(chan string)
+
+ +
+

Each channel will receive a value after some amount +of time, to simulate e.g. blocking RPC operations +executing in concurrent goroutines.

+ +
+
    go func() {
+        time.Sleep(time.Second * 1)
+        c1 <- "one"
+    }()
+    go func() {
+        time.Sleep(time.Second * 2)
+        c2 <- "two"
+    }()
+
+ +
+

We’ll use select to await both of these values +simultaneously, printing each one as it arrives.

+ +
+
    for i := 0; i < 2; i++ {
+        select {
+        case msg1 := <-c1:
+            fmt.Println("received", msg1)
+        case msg2 := <-c2:
+            fmt.Println("received", msg2)
+        }
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

We receive the values "one" and then "two" as +expected.

+ +
+
$ time go run select.go 
+received one
+received two
+
+ +
+

Note that the total execution time is only ~2 seconds +since both the 1 and 2 second Sleeps execute +concurrently.

+ +
+
real	0m2.245s
+
+ +
+ + +

+ Next example: Timeouts. +

+ + +
+ + diff --git a/public/sha1-hashes b/public/sha1-hashes new file mode 100644 index 0000000..9a7d958 --- /dev/null +++ b/public/sha1-hashes @@ -0,0 +1,190 @@ + + + + + Go by Example: SHA1 Hashes + + + + +
+

Go by Example: SHA1 Hashes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

SHA1 hashes are +frequently used to compute short identities for binary +or text blobs. For example, the git revision control +system uses SHA1s extensively to +identify versioned files and directories. Here’s how to +compute SHA1 hashes in Go.

+ +
+ +
+ + +
package main
+
+ +
+

Go implements several hash functions in various +crypto/* packages.

+ +
+
import "crypto/sha1"
+import "fmt"
+
+ +
+ + +
func main() {
+    s := "sha1 this string"
+
+ +
+

The pattern for generating a hash is sha1.New(), +sha1.Write(bytes), then sha1.Sum([]byte{}). +Here we start with a new hash.

+ +
+
    h := sha1.New()
+
+ +
+

Write expects bytes. If you have a string s, +use []byte(s) to coerce it to bytes.

+ +
+
    h.Write([]byte(s))
+
+ +
+

This gets the finalized hash result as a byte +slice. The argument to Sum can be used to append +to an existing byte slice: it usually isn’t needed.

+ +
+
    bs := h.Sum(nil)
+
+ +
+

SHA1 values are often printed in hex, for example +in git commits. Use the %x format verb to convert +a hash results to a hex string.

+ +
+
    fmt.Println(s)
+    fmt.Printf("%x\n", bs)
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Running the program computes the hash and prints it in +a human-readable hex format.

+ +
+
$ go run sha1-hashes.go
+sha1 this string
+cf23df2207d99a74fbe169e3eba035e633b65d94
+
+ +
+

You can compute other hashes using a similar pattern to +the one shown above. For example, to compute MD5 hashes +import crypto/md5 and use md5.New().

+ +
+ +
+

Note that if you need cryptographically secure hashes, +you should carefully research +hash strength!

+ +
+ +
+ + +

+ Next example: Base64 Encoding. +

+ + +
+ + diff --git a/public/signals b/public/signals new file mode 100644 index 0000000..6820a9c --- /dev/null +++ b/public/signals @@ -0,0 +1,177 @@ + + + + + Go by Example: Signals + + + + +
+

Go by Example: Signals

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sometines we’d like our Go programs to intelligently +handle Unix signals. +For example, we might want a server to gracefully +shutdown when it receives a SIGTERM, or a command-line +tool to stop processing input if it receives a SIGINT. +Here’s how to handle signals in Go with channels.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "os"
+import "os/signal"
+import "syscall"
+
+ +
+ + +
func main() {
+
+ +
+

Go signal notification works by sending os.Signal +values on a channel. We’ll create a channel to +receive these notifications (we’ll also make one to +notify us when the program can exit.)

+ +
+
    sigs := make(chan os.Signal, 1)
+    done := make(chan bool, 1)
+
+ +
+

signal.Notify registers the given channel to +receive notifications of the specified signals.

+ +
+
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+
+ +
+

This goroutine executes a blocking receive for +signals. When it gets one it’ll print it out +and then notify the program that it can finish.

+ +
+
    go func() {
+        sig := <-sigs
+        fmt.Println()
+        fmt.Println(sig)
+        done <- true
+    }()
+
+ +
+

The program will wait here until it gets the +expected signal (as indicated by the goroutine +above sending a value on done) and then exit.

+ +
+
    fmt.Println("awaiting signal")
+    <-done
+    fmt.Println("exiting")
+}
+
+ +
+ + + + + + + + +
+

When we run this program it will block waiting for a +signal. By typing ctrl-C (which the +terminal shows as ^C) we can send a SIGINT signal, +causing the program to print interrupt and then exit.

+ +
+
$ go run signals.go
+awaiting signal
+^C
+interrupt
+exiting
+
+ +
+ + +

+ Next example: Exit. +

+ + +
+ + diff --git a/public/site.css b/public/site.css new file mode 100644 index 0000000..1e698f4 --- /dev/null +++ b/public/site.css @@ -0,0 +1,201 @@ +/* CSS reset: http://meyerweb.com/eric/tools/css/reset/ */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* Layout and typography */ +body { + font-family: 'Georgia', serif; + font-size: 16px; + line-height: 20px; + color: #252519; +} +em { + font-style: italic; +} +a, a:visited { + color: #261a3b; +} +h2 { + font-size: 32px; + line-height: 40px; + margin-top: 40px; +} +h2 a { + text-decoration: none; +} +div.example { + width: 900px; + min-width: 900px; + max-width: 900px; + margin-left: auto; + margin-right: auto; + margin-bottom: 120px; +} +div.example table { + margin-top: 15px; + margin-bottom: 20px; +} +p.next { + margin-bottom: 20px; +} +p.footer { + color: grey; +} +p.footer a, p.footer a:visited { + color: grey; +} +div#intro { + width: 420px; + min-width: 420px; + max-width: 420px; + margin-left: auto; + margin-right: auto; + margin-bottom: 120px; +} +div#intro p { + padding-top: 20px; +} +div#intro ul { + padding-top: 20px; +} +table td { + border: 0; + outline: 0; +} +td.docs { + width: 420px; + max-width: 420px; + min-width: 420px; + min-height: 5px; + vertical-align: top; + text-align: left; +} +td.docs p { + padding-right: 5px; + padding-top: 5px; + padding-bottom: 15px; +} +td.code { + width: 480px; + max-width: 480px; + min-width: 480px; + padding-top: 5px; + padding-right: 5px; + padding-left: 5px; + padding-bottom: 5px; + vertical-align: top; + background: #f0f0f0; +} +td.code.leading { + padding-bottom: 11px; +} +td.code.empty { + background: #ffffff; +} +pre, code { + font-size: 14px; line-height: 18px; + font-family: 'Menlo', 'Monaco', 'Consolas', 'Lucida Console', monospace; +} + +/* Syntax highlighting */ +body .hll { background-color: #ffffcc } +body .err { border: 1px solid #FF0000 } /* Error */ +body .c { color: #408080; font-style: italic } /* Comment */ +body .k { color: #954121 } /* Keyword */ +body .o { color: #666666 } /* Operator */ +body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ +body .cp { color: #BC7A00 } /* Comment.Preproc */ +body .c1 { color: #408080; font-style: italic } /* Comment.Single */ +body .cs { color: #408080; font-style: italic } /* Comment.Special */ +body .gd { color: #A00000 } /* Generic.Deleted */ +body .ge { font-style: italic } /* Generic.Emph */ +body .gr { color: #FF0000 } /* Generic.Error */ +body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +body .gi { color: #00A000 } /* Generic.Inserted */ +body .go { color: #808080 } /* Generic.Output */ +body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +body .gs { font-weight: bold } /* Generic.Strong */ +body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +body .gt { color: #0040D0 } /* Generic.Traceback */ +body .kc { color: #954121 } /* Keyword.Constant */ +body .kd { color: #954121 } /* Keyword.Declaration */ +body .kn { color: #954121 } /* Keyword.Namespace */ +body .kp { color: #954121 } /* Keyword.Pseudo */ +body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ +body .kt { color: #B00040 } /* Keyword.Type */ +body .m { color: #666666 } /* Literal.Number */ +body .s { color: #219161 } /* Literal.String */ +body .na { color: #7D9029 } /* Name.Attribute */ +body .nb { color: #954121 } /* Name.Builtin */ +body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +body .no { color: #880000 } /* Name.Constant */ +body .nd { color: #AA22FF } /* Name.Decorator */ +body .ni { color: #999999; font-weight: bold } /* Name.Entity */ +body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +body .nf { color: #0000FF } /* Name.Function */ +body .nl { color: #A0A000 } /* Name.Label */ +body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +body .nt { color: #954121; font-weight: bold } /* Name.Tag */ +body .nv { color: #19469D } /* Name.Variable */ +body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +body .w { color: #bbbbbb } /* Text.Whitespace */ +body .mf { color: #666666 } /* Literal.Number.Float */ +body .mh { color: #666666 } /* Literal.Number.Hex */ +body .mi { color: #666666 } /* Literal.Number.Integer */ +body .mo { color: #666666 } /* Literal.Number.Oct */ +body .sb { color: #219161 } /* Literal.String.Backtick */ +body .sc { color: #219161 } /* Literal.String.Char */ +body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ +body .s2 { color: #219161 } /* Literal.String.Double */ +body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +body .sh { color: #219161 } /* Literal.String.Heredoc */ +body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +body .sx { color: #954121 } /* Literal.String.Other */ +body .sr { color: #BB6688 } /* Literal.String.Regex */ +body .s1 { color: #219161 } /* Literal.String.Single */ +body .ss { color: #19469D } /* Literal.String.Symbol */ +body .bp { color: #954121 } /* Name.Builtin.Pseudo */ +body .vc { color: #19469D } /* Name.Variable.Class */ +body .vg { color: #19469D } /* Name.Variable.Global */ +body .vi { color: #19469D } /* Name.Variable.Instance */ +body .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/public/slices b/public/slices new file mode 100644 index 0000000..1f39e96 --- /dev/null +++ b/public/slices @@ -0,0 +1,291 @@ + + + + + Go by Example: Slices + + + + +
+

Go by Example: Slices

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Slices are a key data type in Go, giving a more +powerful interface to sequences than arrays.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Unlike arrays, slices are typed only by the +elements they contain (not the number of elements). +To create an empty slice with non-zero length, use +the builtin make. Here we make a slice of +strings of length 3 (initially zero-valued).

+ +
+
    s := make([]string, 3)
+    fmt.Println("emp:", s)
+
+ +
+

We can set and get just like with arrays.

+ +
+
    s[0] = "a"
+    s[1] = "b"
+    s[2] = "c"
+    fmt.Println("set:", s)
+    fmt.Println("get:", s[2])
+
+ +
+

len returns the length of the slice as expected.

+ +
+
    fmt.Println("len:", len(s))
+
+ +
+

In addition to these basic operations, slices +support several more that make them richer than +arrays. One is the builtin append, which +returns a slice containing one or more new values. +Note that we need to accept a return value from +append as we may get a new slice value.

+ +
+
    s = append(s, "d")
+    s = append(s, "e", "f")
+    fmt.Println("apd:", s)
+
+ +
+

Slices can also be copy’d. Here we create an +empty slice c of the same length as s and copy +into c from s.

+ +
+
    c := make([]string, len(s))
+    copy(c, s)
+    fmt.Println("cpy:", c)
+
+ +
+

Slices support a “slice” operator with the syntax +slice[low:high]. For example, this gets a slice +of the elements s[2], s[3], and s[4].

+ +
+
    l := s[2:5]
+    fmt.Println("sl1:", l)
+
+ +
+

This slices up to (but excluding) s[5].

+ +
+
    l = s[:5]
+    fmt.Println("sl2:", l)
+
+ +
+

And this slices up from (and including) s[2].

+ +
+
    l = s[2:]
+    fmt.Println("sl3:", l)
+
+ +
+

We can declare and initialize a variable for slice +in a single line as well.

+ +
+
    t := []string{"g", "h", "i"}
+    fmt.Println("dcl:", t)
+
+ +
+

Slices can be composed into multi-dimensional data +structures. The length of the inner slices can +vary, unlike with multi-dimensional arrays.

+ +
+
    twoD := make([][]int, 3)
+    for i := 0; i < 3; i++ {
+        innerLen := i + 1
+        twoD[i] = make([]int, innerLen)
+        for j := 0; j < innerLen; j++ {
+            twoD[i][j] = i + j
+        }
+    }
+    fmt.Println("2d: ", twoD)
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Note that while slices are different types than arrays, +they are rendered similarly by fmt.Println.

+ +
+
$ go run slices.go
+emp: [  ]
+set: [a b c]
+get: c
+len: 3
+apd: [a b c d e f]
+cpy: [a b c d e f]
+sl1: [c d e]
+sl2: [a b c d e]
+sl3: [c d e f]
+dcl: [g h i]
+2d:  [[0] [1 2] [2 3 4]]
+
+ +
+

Check out this great blog post +by the Go team for more details on the design and +implementation of slices in Go.

+ +
+ +
+

Now that we’ve seen arrays and slices we’ll look at +Go’s other key builtin data structure: maps.

+ +
+ +
+ + +

+ Next example: Maps. +

+ + +
+ + diff --git a/public/sorting b/public/sorting new file mode 100644 index 0000000..a8dc00d --- /dev/null +++ b/public/sorting @@ -0,0 +1,150 @@ + + + + + Go by Example: Sorting + + + + +
+

Go by Example: Sorting

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s sort package implements sorting for builtins +and user-defined types. We’ll look at sorting for +builtins first.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "sort"
+
+ +
+ + +
func main() {
+
+ +
+

Sort methods are specific to the builtin type; +here’s an example for strings. Note that sorting is +in-place, so it changes the given slice and doesn’t +return a new one.

+ +
+
    strs := []string{"c", "a", "b"}
+    sort.Strings(strs)
+    fmt.Println("Strings:", strs)
+
+ +
+

An example of sorting ints.

+ +
+
    ints := []int{7, 2, 4}
+    sort.Ints(ints)
+    fmt.Println("Ints:   ", ints)
+
+ +
+

We can also use sort to check if a slice is +already in sorted order.

+ +
+
    s := sort.IntsAreSorted(ints)
+    fmt.Println("Sorted: ", s)
+}
+
+ +
+ + + + + + + + +
+

Running our program prints the sorted string and int +slices and true as the result of our AreSorted test.

+ +
+
$ go run sorting.go
+Strings: [a b c]
+Ints:    [2 4 7]
+Sorted:  true
+
+ +
+ + +

+ Next example: Sorting by Functions. +

+ + +
+ + diff --git a/public/sorting-by-functions b/public/sorting-by-functions new file mode 100644 index 0000000..7d5401b --- /dev/null +++ b/public/sorting-by-functions @@ -0,0 +1,167 @@ + + + + + Go by Example: Sorting by Functions + + + + +
+

Go by Example: Sorting by Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sometimes we’ll want to sort a collection by something +other than its natural order. For example, suppose we +wanted to sort strings by their length instead of +alphabetically. Here’s an example of custom sorts sorts +in Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "sort"
+import "fmt"
+
+ +
+

In order to sort by a custom function in Go, we need a +corresponding type. Here we’ve created a ByLength +type that is just an alias for the builtin []string +type.

+ +
+
type ByLength []string
+
+ +
+

We implement sort.Interface - Len, Less, and +Swap - on our type so we can use the sort package’s +generic Sort function. Len and Swap +will usually be similar accross types and Less will +hold the actual custom sorting logic. In our case we +want to sort in order of increasing string length, so +we use len(s[i]) and len(s[j]) here.

+ +
+
func (s ByLength) Len() int {
+    return len(s)
+}
+func (s ByLength) Swap(i, j int) {
+    s[i], s[j] = s[j], s[i]
+}
+func (s ByLength) Less(i, j int) bool {
+    return len(s[i]) < len(s[j])
+}
+
+ +
+

With all of this in place, we can now implement our +custom sort by casting the original fruits slice to +ByLength, and then use sort.Sort on that typed +slice.

+ +
+
func main() {
+    fruits := []string{"peach", "banana", "kiwi"}
+    sort.Sort(ByLength(fruits))
+    fmt.Println(fruits)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Running our program shows a list sorted by string +length, as desired.

+ +
+
$ go run sorting-by-functions.go 
+[kiwi peach banana]
+
+ +
+

By following this same pattern of creating a custom +type, implementing the three Interface methods on that +type, and then calling sort.Sort on a collection of that +custom type, we can sort Go slices by arbitrary +functions.

+ +
+ +
+ + +

+ Next example: Panic. +

+ + +
+ + diff --git a/public/spawning-processes b/public/spawning-processes new file mode 100644 index 0000000..56e9ae1 --- /dev/null +++ b/public/spawning-processes @@ -0,0 +1,244 @@ + + + + + Go by Example: Spawning Processes + + + + +
+

Go by Example: Spawning Processes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sometimes our Go programs need to spawn other, non-Go +processes. For example, the syntax highlighting on this +site is implemented +by spawning a pygmentize +process from a Go program. Let’s look at a few examples +of spawning processes from Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "io/ioutil"
+import "os/exec"
+
+ +
+ + +
func main() {
+
+ +
+

We’ll start with a simple command that takes no +arguments or input and just prints something to +stdout. The exec.Command helper creates an object +to represent this external process.

+ +
+
    dateCmd := exec.Command("date")
+
+ +
+

.Output is another helper than handles the common +case of running a command, waiting for it to finish, +and collecting its output. If there were no errors, +dateOut will hold bytes with the date info.

+ +
+
    dateOut, err := dateCmd.Output()
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println("> date")
+    fmt.Println(string(dateOut))
+
+ +
+

Next we’ll look at a slightly more involved case +where we pipe data to the external process on its +stdin and collect the results from its stdout.

+ +
+
    grepCmd := exec.Command("grep", "hello")
+
+ +
+

Here we explicitly grab input/output pipes, start +the process, write some input to it, read the +resulting output, and finally wait for the process +to exit.

+ +
+
    grepIn, _ := grepCmd.StdinPipe()
+    grepOut, _ := grepCmd.StdoutPipe()
+    grepCmd.Start()
+    grepIn.Write([]byte("hello grep\ngoodbye grep"))
+    grepIn.Close()
+    grepBytes, _ := ioutil.ReadAll(grepOut)
+    grepCmd.Wait()
+
+ +
+

We ommited error checks in the above example, but +you could use the usual if err != nil pattern for +all of them. We also only collect the StdoutPipe +results, but you could collect the StderrPipe in +exactly the same way.

+ +
+
    fmt.Println("> grep hello")
+    fmt.Println(string(grepBytes))
+
+ +
+

Note that when spawning commands we need to +provide an explicitly delineated command and +argument array, vs. being able to just pass in one +command-line string. If you want to spawn a full +command with a string, you can use bash’s -c +option:

+ +
+
    lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
+    lsOut, err := lsCmd.Output()
+    if err != nil {
+        panic(err)
+    }
+    fmt.Println("> ls -a -l -h")
+    fmt.Println(string(lsOut))
+}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

The spawned programs return output that is the same +as if we had run them directly from the command-line.

+ +
+
$ go run spawning-processes.go 
+> date
+Wed Oct 10 09:53:11 PDT 2012
+
+ +
+ + +
> grep hello
+hello grep
+
+ +
+ + +
> ls -a -l -h
+drwxr-xr-x  4 mark 136B Oct 3 16:29 .
+drwxr-xr-x 91 mark 3.0K Oct 3 12:50 ..
+-rw-r--r--  1 mark 1.3K Oct 3 16:28 spawning-processes.go
+
+ +
+ + +

+ Next example: Exec'ing Processes. +

+ + +
+ + diff --git a/public/stateful-goroutines b/public/stateful-goroutines new file mode 100644 index 0000000..e78f2d8 --- /dev/null +++ b/public/stateful-goroutines @@ -0,0 +1,303 @@ + + + + + Go by Example: Stateful Goroutines + + + + +
+

Go by Example: Stateful Goroutines

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In the previous example we used explicit locking with +mutexes to synchronize access to shared state across +multiple goroutines. Another option is to use the +built-in synchronization features of goroutines and +channels to achieve the same result. This channel-based +approach aligns with Go’s ideas of sharing memory by +communicating and having each piece of data owned +by exactly 1 goroutine.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import (
+    "fmt"
+    "math/rand"
+    "sync/atomic"
+    "time"
+)
+
+ +
+

In this example our state will be owned by a single +goroutine. This will guarantee that the data is never +corrupted with concurrent access. In order to read or +write that state, other goroutines will send messages +to the owning goroutine and receive corresponding +replies. These readOp and writeOp structs +encapsulate those requests and a way for the owning +goroutine to respond.

+ +
+
type readOp struct {
+    key  int
+    resp chan int
+}
+type writeOp struct {
+    key  int
+    val  int
+    resp chan bool
+}
+
+ +
+ + +
func main() {
+
+ +
+

The state will be a map as in the previous +example.

+ +
+
    var state = make(map[int]int)
+
+ +
+

Also as before we’ll count how many operations we +perform.

+ +
+
    var ops int64 = 0
+
+ +
+

The reads and writes channels will be used by +other goroutines to issue read and write requests, +respectively.

+ +
+
    reads := make(chan *readOp)
+    writes := make(chan *writeOp)
+
+ +
+

Here is the goroutine that owns the state. This +goroutine repeatedly selects on the reads and +writes channels, responding to requests as they +arrive. A response is executed by first performing +the requested operation and then sending a value +on the response channel resp to indicate success +(and the desired value in the case of reads).

+ +
+
    go func() {
+        for {
+            select {
+            case read := <-reads:
+                read.resp <- state[read.key]
+            case write := <-writes:
+                state[write.key] = write.val
+                write.resp <- true
+            }
+        }
+    }()
+
+ +
+

This starts 100 goroutines to issue reads to the +state-owning goroutine via the reads channel. +Each read requires constructing a readOp, sending +it over the reads channel, and the receiving the +result over the provided resp channel.

+ +
+
    for r := 0; r < 100; r++ {
+        go func() {
+            for {
+                read := &readOp{
+                    key:  rand.Intn(5),
+                    resp: make(chan int)}
+                reads <- read
+                <-read.resp
+                atomic.AddInt64(&ops, 1)
+            }
+        }()
+    }
+
+ +
+

We start 10 writes as well, using a similar +approach.

+ +
+
    for w := 0; w < 10; w++ {
+        go func() {
+            for {
+                write := &writeOp{
+                    key:  rand.Intn(5),
+                    val:  rand.Intn(100),
+                    resp: make(chan bool)}
+                writes <- write
+                <-write.resp
+                atomic.AddInt64(&ops, 1)
+            }
+        }()
+    }
+
+ +
+

Let the goroutines work for a second.

+ +
+
    time.Sleep(time.Second)
+
+ +
+

Finally, capture and report the ops count.

+ +
+
    opsFinal := atomic.LoadInt64(&ops)
+    fmt.Println("ops:", opsFinal)
+}
+
+ +
+ + + + + + + + + + + + + +
+

Running our program shows that the goroutine-based +state management example achieves about 800,000 +operations per second.

+ +
+
$ go run stateful-goroutines.go
+ops: 807434
+
+ +
+

For this particular case the goroutine-based approach +was a bit more involved than the mutex-based one. It +might be useful in certain cases though, for example +where you have other channels involved or when managing +multiple such mutexes would be error-prone. You should +use whichever approach feels most natural, especially +with respect to understanding the correctness of your +program.

+ +
+ +
+ + +

+ Next example: Sorting. +

+ + +
+ + diff --git a/public/string-formatting b/public/string-formatting new file mode 100644 index 0000000..be4465d --- /dev/null +++ b/public/string-formatting @@ -0,0 +1,427 @@ + + + + + Go by Example: String Formatting + + + + +
+

Go by Example: String Formatting

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go offers excellent support for string formatting in +the printf tradition. Here are some examples of +common string formatting tasks.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "os"
+
+ +
+ + +
type point struct {
+    x, y int
+}
+
+ +
+ + +
func main() {
+
+ +
+

Go offers several printing “verbs” designed to +format general Go values. For example, this prints +an instance of our point struct.

+ +
+
    p := point{1, 2}
+    fmt.Printf("%v\n", p)
+
+ +
+

If the value is a struct, the %+v variant will +include the struct’s field names.

+ +
+
    fmt.Printf("%+v\n", p)
+
+ +
+

The %#v variant prints a Go syntax representation +of the value, i.e. the source code snippet that +would produce that value.

+ +
+
    fmt.Printf("%#v\n", p)
+
+ +
+

To print the type of a value, use %T.

+ +
+
    fmt.Printf("%T\n", p)
+
+ +
+

Formatting booleans is straight-forward.

+ +
+
    fmt.Printf("%t\n", true)
+
+ +
+

There are many options for formatting integers. +Use %d for standard, base-10 formatting.

+ +
+
    fmt.Printf("%d\n", 123)
+
+ +
+

This prints a binary representation.

+ +
+
    fmt.Printf("%b\n", 14)
+
+ +
+

This prints the character corresponding to the +given integer.

+ +
+
    fmt.Printf("%c\n", 33)
+
+ +
+

%x provides hex encoding.

+ +
+
    fmt.Printf("%x\n", 456)
+
+ +
+

There are also several formatting options for +floats. For basic decimal formatting use %f.

+ +
+
    fmt.Printf("%f\n", 78.9)
+
+ +
+

%e and %E format the float in (slightly +different versions of) scientific notation.

+ +
+
    fmt.Printf("%e\n", 123400000.0)
+    fmt.Printf("%E\n", 123400000.0)
+
+ +
+

For basic string printing use %s.

+ +
+
    fmt.Printf("%s\n", "\"string\"")
+
+ +
+

To double-quote strings as in Go source, use %q.

+ +
+
    fmt.Printf("%q\n", "\"string\"")
+
+ +
+

As with integers as seen earlier, %x renders +the string in base-16, with two output characters +per byte of input.

+ +
+
    fmt.Printf("%x\n", "hex this")
+
+ +
+

To print a representation of a pointer, use %p.

+ +
+
    fmt.Printf("%p\n", &p)
+
+ +
+

When formatting numbers you will often want to +control the width and precision of the resulting +figure. To specify the width of an integer, use a +number after the % in the verb. By default the +result will be right-justified and padded with +spaces.

+ +
+
    fmt.Printf("|%6d|%6d|\n", 12, 345)
+
+ +
+

You can also specify the width of printed floats, +though usually you’ll also want to restrict the +decimal precision at the same time with the +width.precision syntax.

+ +
+
    fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
+
+ +
+

To left-justify, use the - flag.

+ +
+
    fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
+
+ +
+

You may also want to control width when formatting +strings, especially to ensure that they align in +table-like output. For basic right-justified width.

+ +
+
    fmt.Printf("|%6s|%6s|\n", "foo", "b")
+
+ +
+

To left-justify use the - flag as with numbers.

+ +
+
    fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
+
+ +
+

So far we’ve seen Printf, which prints the +formatted string to os.Stdout. Sprintf formats +and returns a string without printing it anywhere.

+ +
+
    s := fmt.Sprintf("a %s", "string")
+    fmt.Println(s)
+
+ +
+

You can format+print to io.Writers other than +os.Stdout using Fprintf.

+ +
+
    fmt.Fprintf(os.Stderr, "an %s\n", "error")
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run string-formatting.go
+{1 2}
+{x:1 y:2}
+main.point{x:1, y:2}
+main.point
+true
+123
+1110
+!
+1c8
+78.900000
+1.234000e+08
+1.234000E+08
+"string"
+"\"string\""
+6865782074686973
+0x42135100
+|    12|   345|
+|  1.20|  3.45|
+|1.20  |3.45  |
+|   foo|     b|
+|foo   |b     |
+a string
+an error
+
+ +
+ + +

+ Next example: Regular Expressions. +

+ + +
+ + diff --git a/public/string-functions b/public/string-functions new file mode 100644 index 0000000..9f5f42a --- /dev/null +++ b/public/string-functions @@ -0,0 +1,191 @@ + + + + + Go by Example: String Functions + + + + +
+

Go by Example: String Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

The standard library’s strings package provides many +useful string-related functions. Here are some examples +to give you a sense of the package.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import s "strings"
+import "fmt"
+
+ +
+

We alias fmt.Println to a shorter name as we’ll use +it a lot below.

+ +
+
var p = fmt.Println
+
+ +
+ + +
func main() {
+
+ +
+

Here’s a sample of the functions available in +strings. Note that these are all functions from +package, not methods on the string object itself. +This means that we need pass the string in question +as the first argument to the function.

+ +
+
    p("Contains:  ", s.Contains("test", "es"))
+    p("Count:     ", s.Count("test", "t"))
+    p("HasPrefix: ", s.HasPrefix("test", "te"))
+    p("HasSuffix: ", s.HasSuffix("test", "st"))
+    p("Index:     ", s.Index("test", "e"))
+    p("Join:      ", s.Join([]string{"a", "b"}, "-"))
+    p("Repeat:    ", s.Repeat("a", 5))
+    p("Replace:   ", s.Replace("foo", "o", "0", -1))
+    p("Replace:   ", s.Replace("foo", "o", "0", 1))
+    p("Split:     ", s.Split("a-b-c-d-e", "-"))
+    p("toLower:   ", s.ToLower("TEST"))
+    p("ToUpper:   ", s.ToUpper("test"))
+    p()
+
+ +
+

You can find more functions in the strings +package docs.

+ +
+ +
+

Not part of strings but worth mentioning here are +the mechanisms for getting the length of a string +and getting a character by index.

+ +
+
    p("Len: ", len("hello"))
+    p("Char:", "hello"[1])
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run string-functions.go
+Contains:   true
+Count:      2
+HasPrefix:  true
+HasSuffix:  true
+Index:      1
+Join:       a-b
+Repeat:     aaaaa
+Replace:    f00
+Replace:    f0o
+Split:      [a b c d e]
+toLower:    test
+ToUpper:    TEST
+
+ +
+ + +
Len:  5
+Char: 101
+
+ +
+ + +

+ Next example: String Formatting. +

+ + +
+ + diff --git a/public/structs b/public/structs new file mode 100644 index 0000000..031d0ee --- /dev/null +++ b/public/structs @@ -0,0 +1,209 @@ + + + + + Go by Example: Structs + + + + +
+

Go by Example: Structs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s structs are typed collections of fields. +They’re useful for grouping data together to form +records.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

This person struct type has name and age fields.

+ +
+
type person struct {
+    name string
+    age  int
+}
+
+ +
+ + +
func main() {
+
+ +
+

This syntax creates a new struct.

+ +
+
    fmt.Println(person{"Bob", 20})
+
+ +
+

You can name the fields when initializing a struct.

+ +
+
    fmt.Println(person{name: "Alice", age: 30})
+
+ +
+

Omitted fields will be zero-valued.

+ +
+
    fmt.Println(person{name: "Fred"})
+
+ +
+

An & prefix yields a pointer to the struct.

+ +
+
    fmt.Println(&person{name: "Ann", age: 40})
+
+ +
+

Access struct fields with a dot.

+ +
+
    s := person{name: "Sean", age: 50}
+    fmt.Println(s.name)
+
+ +
+

You can also use dots with struct pointers - the +pointers are automatically dereferenced.

+ +
+
    sp := &s
+    fmt.Println(sp.age)
+
+ +
+

Structs are mutable.

+ +
+
    sp.age = 51
+    fmt.Println(sp.age)
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run structs.go
+{Bob 20}
+{Alice 30}
+{Fred 0}
+&{Ann 40}
+Sean
+50
+51
+
+ +
+ + +

+ Next example: Methods. +

+ + +
+ + diff --git a/public/switch b/public/switch new file mode 100644 index 0000000..66cdc89 --- /dev/null +++ b/public/switch @@ -0,0 +1,162 @@ + + + + + Go by Example: Switch + + + + +
+

Go by Example: Switch

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Switch statements express conditionals across many +branches.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+ + +
func main() {
+
+ +
+

Here’s a basic switch.

+ +
+
    i := 2
+    fmt.Print("write ", i, " as ")
+    switch i {
+    case 1:
+        fmt.Println("one")
+    case 2:
+        fmt.Println("two")
+    case 3:
+        fmt.Println("three")
+    }
+
+ +
+

You can use commas to separate multiple expressions +in the same case statement. We use the optional +default case in this example as well.

+ +
+
    switch time.Now().Weekday() {
+    case time.Saturday, time.Sunday:
+        fmt.Println("it's the weekend")
+    default:
+        fmt.Println("it's a weekday")
+    }
+
+ +
+

switch without an expression is an alternate way +to express if/else logic. Here we also show how the +case expressions can be non-constants.

+ +
+
    t := time.Now()
+    switch {
+    case t.Hour() < 12:
+        fmt.Println("it's before noon")
+    default:
+        fmt.Println("it's after noon")
+    }
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run switch.go 
+write 2 as two
+it's the weekend
+it's before noon
+
+ +
+ + +

+ Next example: Arrays. +

+ + +
+ + diff --git a/public/tickers b/public/tickers new file mode 100644 index 0000000..a167556 --- /dev/null +++ b/public/tickers @@ -0,0 +1,144 @@ + + + + + Go by Example: Tickers + + + + +
+

Go by Example: Tickers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Timers are for when you want to do +something once in the future - tickers are for when +you want to do something repeatedly at regular +intervals. Here’s an example of a ticker that ticks +periodically until we stop it.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "time"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Tickers use a similar mechanism to timers: a +channel that is sent values. Here we’ll use the +range builtin on the channel to iterate over +the values as they arrive every 500ms.

+ +
+
    ticker := time.NewTicker(time.Millisecond * 500)
+    go func() {
+        for t := range ticker.C {
+            fmt.Println("Tick at", t)
+        }
+    }()
+
+ +
+

Tickers can be stopped like timers. Once a ticker +is stopped it won’t receive any more values on its +channel. We’ll stop ours after 1500ms.

+ +
+
    time.Sleep(time.Millisecond * 1500)
+    ticker.Stop()
+    fmt.Println("Ticker stopped")
+}
+
+ +
+ + + + + + + + +
+

When we run this program the ticker should tick 3 times +befor we stop it.

+ +
+
$ go run tickers.go
+Tick at 2012-09-23 11:29:56.487625 -0700 PDT
+Tick at 2012-09-23 11:29:56.988063 -0700 PDT
+Tick at 2012-09-23 11:29:57.488076 -0700 PDT
+Ticker stopped
+
+ +
+ + +

+ Next example: Worker Pools. +

+ + +
+ + diff --git a/public/time b/public/time new file mode 100644 index 0000000..9b6c9f6 --- /dev/null +++ b/public/time @@ -0,0 +1,254 @@ + + + + + Go by Example: Time + + + + +
+

Go by Example: Time

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go’s offers extensive support for times and durations; +here are some examples.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+ + +
func main() {
+    p := fmt.Println
+
+ +
+

We’ll start by getting the current time.

+ +
+
    now := time.Now()
+    p(now)
+
+ +
+

You can build a time struct by providing the +year, month, day, etc. Times are always associated +with a Location, i.e. time zone.

+ +
+
    then := time.Date(
+        2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
+    p(then)
+
+ +
+

You can extract the various components of the time +value as expected.

+ +
+
    p(then.Year())
+    p(then.Month())
+    p(then.Day())
+    p(then.Hour())
+    p(then.Minute())
+    p(then.Second())
+    p(then.Nanosecond())
+    p(then.Location())
+
+ +
+

The Monday-Sunday Weekday is also available.

+ +
+
    p(then.Weekday())
+
+ +
+

These methods compare two times, testing if the +first occurs before, after, or at the same time +as the second, respectively.

+ +
+
    p(then.Before(now))
+    p(then.After(now))
+    p(then.Equal(now))
+
+ +
+

The Sub methods returns a Duration representing +the interval between two times.

+ +
+
    diff := now.Sub(then)
+    p(diff)
+
+ +
+

We can compute the length of the duration in +various units.

+ +
+
    p(diff.Hours())
+    p(diff.Minutes())
+    p(diff.Seconds())
+    p(diff.Nanoseconds())
+
+ +
+

You can use Add to advance a time by a given +duration, or with a - to move backwards by a +duration.

+ +
+
    p(then.Add(diff))
+    p(then.Add(-diff))
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run time.go
+2012-10-31 15:50:13.793654 +0000 UTC
+2009-11-17 20:34:58.651387237 +0000 UTC
+2009
+November
+17
+20
+34
+58
+651387237
+UTC
+Tuesday
+true
+false
+false
+25891h15m15.142266763s
+25891.25420618521
+1.5534752523711128e+06
+9.320851514226677e+07
+93208515142266763
+2012-10-31 15:50:13.793654 +0000 UTC
+2006-12-05 01:19:43.509120474 +0000 UTC
+
+ +
+

Next we’ll look at the related idea of time relative to +the Unix epoch.

+ +
+ +
+ + +

+ Next example: Epoch. +

+ + +
+ + diff --git a/public/time-formatting-parsing b/public/time-formatting-parsing new file mode 100644 index 0000000..ae325c5 --- /dev/null +++ b/public/time-formatting-parsing @@ -0,0 +1,207 @@ + + + + + Go by Example: Time Formatting / Parsing + + + + +
+

Go by Example: Time Formatting / Parsing

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go supports time formatting and parsing via +pattern-based layouts.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+ + +
func main() {
+    p := fmt.Println
+
+ +
+

Here’s a basic example of formatting a time +according to RFC3339.

+ +
+
    t := time.Now()
+    p(t.Format("2006-01-02T15:04:05Z07:00"))
+
+ +
+

Format uses an example-based layout approach; it +takes a formatted version of the reference time +Mon Jan 2 15:04:05 MST 2006 to determine the +general pattern with which to format the given +time. Here are a few more examples of time +formatting.

+ +
+
    p(t.Format("3:04PM"))
+    p(t.Format("Mon Jan _2 15:04:05 2006"))
+    p(t.Format("2006-01-02T15:04:05.999999-07:00"))
+
+ +
+

For purely numeric representations you can also +use standard string formatting with the extracted +components of the time value.

+ +
+
    fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
+        t.Year(), t.Month(), t.Day(),
+        t.Hour(), t.Minute(), t.Second())
+
+ +
+

Time parsing uses the same example-based approach +as Formating. These examples parse times rendered +with some of the layouts used above.

+ +
+
    withNanos := "2006-01-02T15:04:05.999999999-07:00"
+    t1, e := time.Parse(
+        withNanos,
+        "2012-11-01T22:08:41.117442+00:00")
+    p(t1)
+    kitchen := "3:04PM"
+    t2, e := time.Parse(kitchen, "8:41PM")
+    p(t2)
+
+ +
+

Parse will return an error on malformed input +explaining the parsing problem.

+ +
+
    ansic := "Mon Jan _2 15:04:05 2006"
+    _, e = time.Parse(ansic, "8:41PM")
+    p(e)
+
+ +
+

There are several predefined formats that you can +use for both formatting and parsing.

+ +
+
    p(t.Format(time.Kitchen))
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run time-formatting-parsing.go 
+2012-11-02T09:35:03-07:00
+9:35AM
+Fri Nov  2 09:35:03 2012
+2012-11-02T09:35:03.982519-07:00
+2012-11-02T09:35:03-00:00
+0001-01-01 00:00:00 +0000 UTC
+0000-01-01 20:41:00 +0000 UTC
+parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": ...
+9:35AM
+
+ +
+ + +

+ Next example: Random Numbers. +

+ + +
+ + diff --git a/public/timeouts b/public/timeouts new file mode 100644 index 0000000..4d9dda1 --- /dev/null +++ b/public/timeouts @@ -0,0 +1,182 @@ + + + + + Go by Example: Timeouts + + + + +
+

Go by Example: Timeouts

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Timeouts are important for programs that connect to +external resources or that otherwise need to bound +execution time. Implementing timeouts in Go is easy and +elegant thanks to channels and select.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "time"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

For our example, suppose we’re executing an external +call that returns its result on a channel c1 +after 2s.

+ +
+
    c1 := make(chan string)
+    go func() {
+        time.Sleep(time.Second * 2)
+        c1 <- "result 1"
+    }()
+
+ +
+

Here’s the select implementing a timeout. +res := <-c1 awaits the result and <-Time.After +awaits a value to be sent after the timeout of +1s. Since select proceeds with the first +receive that’s ready, we’ll take the timeout case +if the operation takes more than the allowed 1s.

+ +
+
    select {
+    case res := <-c1:
+        fmt.Println(res)
+    case <-time.After(time.Second * 1):
+        fmt.Println("timeout 1")
+    }
+
+ +
+

If we allow a longer timeout of 3s, then the receive +from c2 will succeed and we’ll print the result.

+ +
+
    c2 := make(chan string)
+    go func() {
+        time.Sleep(time.Second * 2)
+        c2 <- "result 2"
+    }()
+    select {
+    case res := <-c2:
+        fmt.Println(res)
+    case <-time.After(time.Second * 3):
+        fmt.Println("timeout 2")
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Running this program shows the first operation timing +out and the second succeeding.

+ +
+
$ go run timeouts.go 
+timeout 1
+result 2
+
+ +
+

Using this select timeout pattern requires +communicating results over channels. This is a good +idea in general because other important Go features are +based on channels and select. We’ll look at two +examples of this next: timers and tickers.

+ +
+ +
+ + +

+ Next example: Non-Blocking Channel Operations. +

+ + +
+ + diff --git a/public/timers b/public/timers new file mode 100644 index 0000000..2c1452a --- /dev/null +++ b/public/timers @@ -0,0 +1,160 @@ + + + + + Go by Example: Timers + + + + +
+

Go by Example: Timers

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

We often want to execute Go code at some point in the +future, or repeatedly at some interval. Go’s built-in +timer and ticker features make both of these tasks +easy. We’ll look first at timers and then +at tickers.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "time"
+import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Timers represent a single event in the future. You +tell the timer how long you want to wait, and it +provides a channel that will be notified at that +time. This timer will wait 2 seconds.

+ +
+
    timer1 := time.NewTimer(time.Second * 2)
+
+ +
+

The <-timer1.C blocks on the timer’s channel C +until it sends a value indicating that the timer +expired.

+ +
+
    <-timer1.C
+    fmt.Println("Timer 1 expired")
+
+ +
+

If you just wanted to wait, you could have used +time.Sleep. One reason a timer may be useful is +that you can cancel the timer before it expires. +Here’s an example of that.

+ +
+
    timer2 := time.NewTimer(time.Second)
+    go func() {
+        <-timer2.C
+        fmt.Println("Timer 2 expired")
+    }()
+    stop2 := timer2.Stop()
+    if stop2 {
+        fmt.Println("Timer 2 stopped")
+    }
+}
+
+ +
+ + + + + + + + +
+

The first timer will expire ~2s after we start the +program, but the second should be stopped before it has +a chance to expire.

+ +
+
$ go run timers.go
+Timer 1 expired
+Timer 2 stopped
+
+ +
+ + +

+ Next example: Tickers. +

+ + +
+ + diff --git a/public/url-parsing b/public/url-parsing new file mode 100644 index 0000000..ed41e56 --- /dev/null +++ b/public/url-parsing @@ -0,0 +1,222 @@ + + + + + Go by Example: URL Parsing + + + + +
+

Go by Example: URL Parsing

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

URLs provide a uniform way to locate resources. +Here’s how to parse URLs in Go.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "net/url"
+import "strings"
+
+ +
+ + +
func main() {
+
+ +
+

We’ll parse this example URL, which includes a +scheme, authentication info, host, port, path, +query params, and query fragment.

+ +
+
    s := "postgres://user:pass@host.com:5432/path?k=v#f"
+
+ +
+

Parse the URL and ensure there are no errors.

+ +
+
    u, err := url.Parse(s)
+    if err != nil {
+        panic(err)
+    }
+
+ +
+

Accessing the scheme is straightforward.

+ +
+
    fmt.Println(u.Scheme)
+
+ +
+

User contains all authentication info; call +Username and Password on this for individual +values.

+ +
+
    fmt.Println(u.User)
+    fmt.Println(u.User.Username())
+    p, _ := u.User.Password()
+    fmt.Println(p)
+
+ +
+

The Host contains both the hostname and the port, +if present. Split the Host manually to extract +the port.

+ +
+
    fmt.Println(u.Host)
+    h := strings.Split(u.Host, ":")
+    fmt.Println(h[0])
+    fmt.Println(h[1])
+
+ +
+

Here we extract the path and the fragment after +the #.

+ +
+
    fmt.Println(u.Path)
+    fmt.Println(u.Fragment)
+
+ +
+

To get query params in a string of k=v format, +use RawQuery. You can also parse query params +into a map. The parsed query param maps are from +strings to slices of strings, so index into [0] +if you only want the first value.

+ +
+
    fmt.Println(u.RawQuery)
+    m, _ := url.ParseQuery(u.RawQuery)
+    fmt.Println(m)
+    fmt.Println(m["k"][0])
+}
+
+ +
+ + + + + + + + +
+

Running our URL parsing program shows all the different +pieces that we extracted.

+ +
+
$ go run url-parsing.go 
+postgres
+user:pass
+user
+pass
+host.com:5432
+host.com
+5432
+/path
+f
+k=v
+map[k:[v]]
+v
+
+ +
+ + +

+ Next example: SHA1 Hashes. +

+ + +
+ + diff --git a/public/values b/public/values new file mode 100644 index 0000000..6f6c644 --- /dev/null +++ b/public/values @@ -0,0 +1,144 @@ + + + + + Go by Example: Values + + + + +
+

Go by Example: Values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Go has various value types including strings, +integers, floats, booleans, etc. Here are a few +basic examples.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

Strings, which can be added together with +.

+ +
+
    fmt.Println("go" + "lang")
+
+ +
+

Integers and floats.

+ +
+
    fmt.Println("1+1 =", 1+1)
+    fmt.Println("7.0/3.0 =", 7.0/3.0)
+
+ +
+

Booleans, with boolean operators as you’d expect.

+ +
+
    fmt.Println(true && false)
+    fmt.Println(true || false)
+    fmt.Println(!true)
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run values.go
+golang
+1+1 = 2
+7.0/3.0 = 2.3333333333333335
+false
+true
+false
+
+ +
+ + +

+ Next example: Variables. +

+ + +
+ + diff --git a/public/variables b/public/variables new file mode 100644 index 0000000..7c079ca --- /dev/null +++ b/public/variables @@ -0,0 +1,173 @@ + + + + + Go by Example: Variables + + + + +
+

Go by Example: Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In Go, variables are explicitly declared and used by +the compiler to e.g. check type-correctness of function +calls.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+ + +
func main() {
+
+ +
+

var declares 1 or more variables.

+ +
+
    var a string = "initial"
+    fmt.Println(a)
+
+ +
+

You can declare multiple variables at once.

+ +
+
    var b, c int = 1, 2
+    fmt.Println(b, c)
+
+ +
+

Go will infer the type of initialized variables.

+ +
+
    var d = true
+    fmt.Println(d)
+
+ +
+

Variables declared without a corresponding +initialization are zero-valued. For example, the +zero value for an int is 0.

+ +
+
    var e int
+    fmt.Println(e)
+
+ +
+

The := syntax is shorthand for declaring and +initializing a variable, e.g. for +var f string = "short" in this case.

+ +
+
    f := "short"
+    fmt.Println(f)
+}
+
+ +
+ + + + + + + + +
+ + +
$ go run variables.go
+initial
+1 2
+true
+0
+short
+
+ +
+ + +

+ Next example: Constants. +

+ + +
+ + diff --git a/public/variadic-functions b/public/variadic-functions new file mode 100644 index 0000000..c273143 --- /dev/null +++ b/public/variadic-functions @@ -0,0 +1,163 @@ + + + + + Go by Example: Variadic Functions + + + + +
+

Go by Example: Variadic Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Variadic functions +can be called with any number of trailing arguments. +For example, fmt.Println is a common variadic +function.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+
+ +
+

Here’s a function that will take an arbitrary number +of ints as arguments.

+ +
+
func sum(nums ...int) {
+    fmt.Print(nums, " ")
+    total := 0
+    for _, num := range nums {
+        total += num
+    }
+    fmt.Println(total)
+}
+
+ +
+ + +
func main() {
+
+ +
+

Variadic functions can be called in the usual way +with individual arguments.

+ +
+
    sum(1, 2)
+    sum(1, 2, 3)
+
+ +
+

If you already have multiple args in a slice, +apply them to a variadic function using +func(slice...) like this.

+ +
+
    nums := []int{1, 2, 3, 4}
+    sum(nums...)
+}
+
+ +
+ + + + + + + + + + + + + +
+ + +
$ go run variadic-functions.go 
+[1 2] 3
+[1 2 3] 6
+[1 2 3 4] 10
+
+ +
+

Another key aspect of functions in Go is their ability +to form closures, which we’ll look at next.

+ +
+ +
+ + +

+ Next example: Closures. +

+ + +
+ + diff --git a/public/worker-pools b/public/worker-pools new file mode 100644 index 0000000..258a305 --- /dev/null +++ b/public/worker-pools @@ -0,0 +1,205 @@ + + + + + Go by Example: Worker Pools + + + + +
+

Go by Example: Worker Pools

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

In this example we’ll look at how to implement +a worker pool using goroutines and channels.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import "fmt"
+import "time"
+
+ +
+

Here’s the worker, of which we’ll run several +concurrent instances. These workers will receive +work on the jobs channel and send the corresponding +results on results. We’ll sleep a second per job to +simulate an expensive task.

+ +
+
func worker(id int, jobs <-chan int, results chan<- int) {
+    for j := range jobs {
+        fmt.Println("worker", id, "processing job", j)
+        time.Sleep(time.Second)
+        results <- j * 2
+    }
+}
+
+ +
+ + +
func main() {
+
+ +
+

In order to use our pool of workers we need to send +them work and collect their results. We make 2 +channels for this.

+ +
+
    jobs := make(chan int, 100)
+    results := make(chan int, 100)
+
+ +
+

This starts up 3 workers, initially blocked +because there are no jobs yet.

+ +
+
    for w := 1; w <= 3; w++ {
+        go worker(w, jobs, results)
+    }
+
+ +
+

Here we send 9 jobs and then close that +channel to indicate that’s all the work we have.

+ +
+
    for j := 1; j <= 9; j++ {
+        jobs <- j
+    }
+    close(jobs)
+
+ +
+

Finally we collect all the results of the work.

+ +
+
    for a := 1; a <= 9; a++ {
+        <-results
+    }
+}
+
+ +
+ + + + + + + + + + + + + +
+

Our running program shows the 9 jobs being executed by +various workers. The program only takes about 3 seconds +despite doing about 9 seconds of total work because +there are 3 workers operating concurrently.

+ +
+
$ time go run worker-pools.go 
+worker 1 processing job 1
+worker 2 processing job 2
+worker 3 processing job 3
+worker 1 processing job 4
+worker 2 processing job 5
+worker 3 processing job 6
+worker 1 processing job 7
+worker 2 processing job 8
+worker 3 processing job 9
+
+ +
+ + +
real	0m3.149s
+
+ +
+ + +

+ Next example: Rate Limiting. +

+ + +
+ + diff --git a/public/writing-files b/public/writing-files new file mode 100644 index 0000000..3753007 --- /dev/null +++ b/public/writing-files @@ -0,0 +1,270 @@ + + + + + Go by Example: Writing Files + + + + +
+

Go by Example: Writing Files

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Writing files in Go follows similar patterns to the +ones we saw earlier for reading.

+ +
+ +
+ + +
package main
+
+ +
+ + +
import (
+    "bufio"
+    "fmt"
+    "io/ioutil"
+    "os"
+)
+
+ +
+ + +
func check(e error) {
+    if e != nil {
+        panic(e)
+    }
+}
+
+ +
+ + +
func main() {
+
+ +
+

To start, here’s how to dump a string (or just +bytes) into a file.

+ +
+
    d1 := []byte("hello\ngo\n")
+    err := ioutil.WriteFile("/tmp/dat1", d1, 0644)
+    check(err)
+
+ +
+

For more granular writes, open a file for writing.

+ +
+
    f, err := os.Create("/tmp/dat2")
+    check(err)
+
+ +
+

It’s idiomatic to defer a Close immediately +after opening a file.

+ +
+
    defer f.Close()
+
+ +
+

You can Write byte slices as you’d expect.

+ +
+
    d2 := []byte{115, 111, 109, 101, 10}
+    n2, err := f.Write(d2)
+    check(err)
+    fmt.Printf("wrote %d bytes\n", n2)
+
+ +
+

A WriteString is also available.

+ +
+
    n3, err := f.WriteString("writes\n")
+    fmt.Printf("wrote %d bytes\n", n3)
+
+ +
+

Issue a Sync to flush writes to stable storage.

+ +
+
    f.Sync()
+
+ +
+

bufio provides buffered writers in addition +to the buffered readers we saw earlier.

+ +
+
    w := bufio.NewWriter(f)
+    n4, err := w.WriteString("buffered\n")
+    fmt.Printf("wrote %d bytes\n", n4)
+
+ +
+

Use Flush to ensure all buffered operations have +been applied to the underlying writer.

+ +
+
    w.Flush()
+
+ +
+ + +
}
+
+ +
+ + + + + + + + + + + + + + + + + + +
+

Try running the file-writing code.

+ +
+
$ go run writing-files.go 
+wrote 5 bytes
+wrote 7 bytes
+wrote 9 bytes
+
+ +
+

Then check the contents of the written files.

+ +
+
$ cat /tmp/dat1
+hello
+go
+$ cat /tmp/dat2
+some
+writes
+buffered
+
+ +
+

Next we’ll look at applying some of the file I/O ideas +we’ve just seen to the stdin and stdout streams.

+ +
+ +
+ + +

+ Next example: Line Filters. +

+ + +
+ + diff --git a/server.go b/server.go new file mode 100644 index 0000000..20ffc35 --- /dev/null +++ b/server.go @@ -0,0 +1,207 @@ +package main + +import ( + "code.google.com/p/gorilla/mux" + "encoding/base64" + "fmt" + "io/ioutil" + "net" + "net/http" + "os" + "os/signal" + "strings" + "sync/atomic" + "syscall" + "time" +) + +func check(err error) { + if err != nil { + panic(err) + } +} + +func config(k string) string { + v := os.Getenv(k) + if v == "" { + panic("missing " + k) + } + return v +} + +func runLogging(logs chan string) { + for log := range logs { + fmt.Println(log) + } +} + +func wrapLogging(f http.HandlerFunc, logs chan string) http.HandlerFunc { + return func(res http.ResponseWriter, req *http.Request) { + start := time.Now() + f(res, req) + method := req.Method + path := req.URL.Path + elapsed := float64(time.Since(start)) / 1000000.0 + logs <- fmt.Sprintf("request at=finish method=%s path=%s elapsed=%f", method, path, elapsed) + } +} + +func wrapCanonicalHost(f http.HandlerFunc, canonicalHost string, forceHttps bool) http.HandlerFunc { + return func(res http.ResponseWriter, req *http.Request) { + scheme := "http" + if h, ok := req.Header["X-Forwarded-Proto"]; ok { + if h[0] == "https" { + scheme = "https" + } + } + + hostPort := strings.Split(req.Host, ":") + host := hostPort[0] + + if (forceHttps && (scheme != "https")) || host != canonicalHost { + if forceHttps { + scheme = "https" + } + hostPort[0] = canonicalHost + url := scheme + "://" + strings.Join(hostPort, ":") + req.URL.String() + http.Redirect(res, req, url, 301) + return + } + + f(res, req) + } +} + +type Authenticator func(string, string) bool + +func testAuth(r *http.Request, auth Authenticator) bool { + s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) + if len(s) != 2 || s[0] != "Basic" { + return false + } + b, err := base64.StdEncoding.DecodeString(s[1]) + if err != nil { + return false + } + pair := strings.SplitN(string(b), ":", 2) + if len(pair) != 2 { + return false + } + return auth(pair[0], pair[1]) +} + +func requireAuth(w http.ResponseWriter, r *http.Request) { + w.Header().Set("WWW-Authenticate", `Basic realm="private"`) + w.WriteHeader(401) + w.Write([]byte("401 Unauthorized\n")) +} + +func wrapAuth(h http.HandlerFunc, a Authenticator) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if testAuth(r, a) { + h(w, r) + } else { + requireAuth(w, r) + } + } +} + +var reqCount int64 = 0 + +func wrapReqCount(h http.HandlerFunc, reqCountPtr *int64) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + atomic.AddInt64(reqCountPtr, 1) + h(w, r) + atomic.AddInt64(reqCountPtr, -1) + } +} + +func static(res http.ResponseWriter, req *http.Request) { + http.ServeFile(res, req, "public"+req.URL.Path) +} + +func notFound(res http.ResponseWriter, req *http.Request) { + http.ServeFile(res, req, "public/404.html") +} + +func checkAuth(user, pass string) bool { + auth := os.Getenv("AUTH") + if auth == "" { + return true + } + return auth == strings.Join([]string{user, pass}, ":") +} + +func routerHandlerFunc(router *mux.Router) http.HandlerFunc { + return func(res http.ResponseWriter, req *http.Request) { + router.ServeHTTP(res, req) + } +} + +func router() *mux.Router { + router := mux.NewRouter() + router.HandleFunc("/", static).Methods("GET") + router.HandleFunc("/favicon.ico", static).Methods("GET") + router.HandleFunc("/site.css", static).Methods("GET") + entries, err := ioutil.ReadDir("public") + check(err) + for _, f := range entries { + if !strings.Contains(f.Name(), ".") { + router.HandleFunc("/" + f.Name(), static).Methods("GET") + } + } + router.NotFoundHandler = http.HandlerFunc(notFound) + return router +} + +func main() { + logs := make(chan string, 10000) + go runLogging(logs) + + handler := routerHandlerFunc(router()) + if os.Getenv("AUTH") != "" { + handler = wrapAuth(handler, checkAuth) + } + handler = wrapCanonicalHost(handler, config("CANONICAL_HOST"), config("FORCE_HTTPS") == "1") + handler = wrapLogging(handler, logs) + handler = wrapReqCount(handler, &reqCount) + + server := &http.Server{Handler: handler} + listener, listenErr := net.Listen("tcp", ":"+config("PORT")) + if listenErr != nil { + panic(listenErr) + } + + stop := make(chan bool, 1) + sig := make(chan os.Signal, 1) + go func() { + signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + logs <- "trap at=start" + <-sig + for { + reqCountCurrent := atomic.LoadInt64(&reqCount) + if reqCountCurrent > 0 { + logs <- fmt.Sprintf("trap at=draining remaining=%d", reqCountCurrent) + time.Sleep(time.Second) + } else { + logs <- fmt.Sprintf("trap at=finish") + stop <- true + return + } + } + }() + + go func() { + logs <- "serve at=start" + server.Serve(listener) + logs <- "serve at=finish" + }() + + <-stop + logs <- "close at=start" + closeErr := listener.Close() + if closeErr != nil { + panic(closeErr) + } + logs <- "close at=finish" +} diff --git a/tools/generate.go b/tools/generate.go index e6d5e8c..6e8d816 100644 --- a/tools/generate.go +++ b/tools/generate.go @@ -14,7 +14,7 @@ import ( ) var cacheDir = "/tmp/gobyexample-cache" -var siteDir = "" +var siteDir = "./public" var pygmentizeBin = "" func check(err error) { @@ -106,15 +106,6 @@ func whichLexer(path string) string { return "" } -func whichSiteDir() { - dir := os.Getenv("SITEDIR") - if dir != "" { - siteDir = dir - } else { - siteDir = "site" - } -} - func whichPygmentize() { bin, err := exec.LookPath("pygmentize") check(err) @@ -254,9 +245,7 @@ func renderExamples(examples []*Example) { } func main() { - whichSiteDir() whichPygmentize() - ensureDir(siteDir) copyFile("templates/site.css", siteDir+"/site.css") copyFile("templates/favicon.ico", siteDir+"/favicon.ico") copyFile("templates/404.html", siteDir+"/404.html")