Merge branch 'master' into clipboard

This commit is contained in:
Mark McGranaghan 2019-09-01 15:42:08 -07:00
commit ee5c86daa9
251 changed files with 6523 additions and 3873 deletions

2
.env
View File

@ -1,2 +0,0 @@
CANONICAL_HOST=127.0.0.1
FORCE_HTTPS=0

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
public/* linguist-generated=true
vendor/* linguist-vendored=true

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
.anvil
*.pyc
.idea
.vscode

1
.godir
View File

@ -1 +0,0 @@
gobyexample

18
.travis.yml Normal file
View File

@ -0,0 +1,18 @@
language: go
go:
- 1.12
before_install:
# We need Python to run pygmentize for generating HTML.
- sudo apt-get update
- sudo apt-get install python
install:
- go get -u github.com/russross/blackfriday
script:
- tools/build
env:
- VERBOSE=1 TESTING=1

View File

@ -1,18 +1,18 @@
## Contributing
Go by Example is now in a steady state. We are maintaining it, but are not
expanding or significantly changing it any more.
Thanks for your interest in contributing to Go by Example!
With that in mind here are some specific contribution guidelines:
* When sending a PR that affects the displayed contents of the site, run
`tools/build` locally and include the generated HTML in the PR. If you
only want to submit a simple typo suggestion (for example, through the
Github website), feel free to send a PR anyway - we'll regenerate the
HTML and merge with your commit.
* If you see a typo or would like to suggest another small change, editing the
.go or .sh source file should be sufficient for the PR. I can rebuild the
HTML when I review the change.
* We're open to adding more examples to the site. They should be on things
used by many programmers and only require the standard library. If you're
interested in adding an example, _please open an issue to discuss the topic
first_.
* We are not going to add any more sections to the site. There are many
important topics that Go by Example doesn't cover, which we leave to other
resources.
* We are not going to change the navigation of the site, in particular adding
* We're not going to change the navigation of the site, in particular adding
a "previous section" link or an "index" link other than the on the title
text.

View File

@ -1,9 +1,8 @@
## Go by Example
# Go by Example
Content and build toolchain for [Go by Example](https://gobyexample.com),
a site that teaches Go via annotated example programs.
### Overview
The Go by Example site is built by extracting code and
@ -17,9 +16,10 @@ The built `public` directory can be served by any
static content system. The production site uses S3 and
CloudFront, for example.
### Building
[![Build Status](https://travis-ci.com/mmcgrana/gobyexample.svg "Travis CI status")](https://travis-ci.com/mmcgrana/gobyexample)
To build the site you'll need Go and Python installed. Run:
```console
@ -34,6 +34,16 @@ To build continuously in a loop:
$ tools/build-loop
```
### Publishing
To upload the site:
```console
$ gem install aws-sdk
$ export AWS_ACCESS_KEY_ID=...
$ export AWS_SECRET_ACCESS_KEY=...
$ tools/upload
```
### License
@ -48,10 +58,13 @@ The Go Gopher is copyright [Renée French](http://reneefrench.blogspot.com/) and
Contributor translations of the Go by Example site are available in:
* [Chinese](http://gobyexample.everyx.in/) by [everyx](https://github.com/everyx)
* [Chinese](https://gobyexample.xgwang.me/) by [xg-wang](https://github.com/xg-wang/gobyexample)
* [French](http://le-go-par-l-exemple.keiruaprod.fr) by [keirua](https://github.com/keirua/gobyexample)
* [Italian](http://gobyexample.it) by the [Go Italian community](https://github.com/golangit/gobyexample-it)
* [Japanese](http://spinute.org/go-by-example) by [spinute](https://github.com/spinute)
* [Korean](https://mingrammer.com/gobyexample/) by [mingrammer](https://github.com/mingrammer)
* [Spanish](http://goconejemplos.com) by the [Go Mexico community](https://github.com/dabit/gobyexample)
* [Ukrainian](http://gobyexample.com.ua/) by [butuzov](https://github.com/butuzov/gobyexample)
### Thanks

View File

@ -32,6 +32,7 @@ Range over Channels
Timers
Tickers
Worker Pools
WaitGroups
Rate Limiting
Atomic Counters
Mutexes
@ -56,9 +57,15 @@ Base64 Encoding
Reading Files
Writing Files
Line Filters
File Paths
Directories
Temporary Files and Directories
Command-Line Arguments
Command-Line Flags
Command-Line Subcommands
Environment Variables
HTTP Clients
HTTP Servers
Spawning Processes
Exec'ing Processes
Signals

View File

@ -7,36 +7,36 @@ import "fmt"
func main() {
// Here we create an array `a` that will hold exactly
// 5 `int`s. The type of elements and length are both
// part of the array's type. By default an array is
// zero-valued, which for `int`s means `0`s.
var a [5]int
fmt.Println("emp:", a)
// Here we create an array `a` that will hold exactly
// 5 `int`s. The type of elements and length are both
// part of the array's type. By default an array is
// zero-valued, which for `int`s means `0`s.
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])
// 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))
// The builtin `len` returns the length of an array.
fmt.Println("len:", len(a))
// Use this syntax to declare and initialize an array
// in one line.
b := [5]int{1, 2, 3, 4, 5}
fmt.Println("dcl:", b)
// Use this syntax to declare and initialize 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)
// 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)
}

View File

@ -1,2 +1,2 @@
305975d13d24223181d13f042b290906d86c1a0e
l-A8eBnwio
W7NwfDq8Vdw

View File

@ -13,37 +13,37 @@ import "sync/atomic"
func main() {
// We'll use an unsigned integer to represent our
// (always-positive) counter.
var ops uint64 = 0
// We'll use an unsigned integer to represent our
// (always-positive) counter.
var ops uint64
// 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 {
// To atomically increment the counter we
// use `AddUint64`, giving it the memory
// address of our `ops` counter with the
// `&` syntax.
atomic.AddUint64(&ops, 1)
// 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 {
// 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 bit between increments.
time.Sleep(time.Millisecond)
}
}()
}
// Wait a bit between increments.
time.Sleep(time.Millisecond)
}
}()
}
// Wait a second to allow some ops to accumulate.
time.Sleep(time.Second)
// 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)
// 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)
}

View File

@ -1,2 +1,2 @@
ce8821f1f4fd99d554ad6cde52403dd3b69bb70a
8p48eFFxDZ
a4190094ea0405b5f2733101beb97939a1d43aee
KDr9EMMPMgi

View File

@ -11,27 +11,27 @@ import "fmt"
func main() {
// Here's the `string` we'll encode/decode.
data := "abc123!?$*&()'-=@~"
// 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)
// Go supports both standard and URL-compatible
// base64. Here's how to encode using the standard
// encoder. The encoder requires a `[]byte` so we
// convert 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()
// 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))
// 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))
}

View File

@ -1,2 +1,2 @@
e57f5be3a796261fb4a55cdb0580a254e14b4930
t6rFm2x4Yr
c20da14820b656c867790f2e99bc37140babca8c
y_QTcqdkvZh

View File

@ -11,17 +11,17 @@ import "fmt"
func main() {
// Here we `make` a channel of strings buffering up to
// 2 values.
messages := make(chan string, 2)
// 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"
// 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)
// Later we can receive these two values as usual.
fmt.Println(<-messages)
fmt.Println(<-messages)
}

View File

@ -1,2 +1,2 @@
122140f7ad1bc5cff4fcd7a9e7245b87aaca3ec5
34PVHwO6Bn
mPoF-Xi-rip

View File

@ -11,20 +11,20 @@ import "fmt"
// values. It would be a compile-time error to try to
// receive on this channel.
func ping(pings chan<- string, msg string) {
pings <- msg
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
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)
pings := make(chan string, 1)
pongs := make(chan string, 1)
ping(pings, "passed message")
pong(pings, pongs)
fmt.Println(<-pongs)
}

View File

@ -1,2 +1,2 @@
635cc13dfe33123ac188e01e3002d3aa935d765f
P9Fujfpa1f
Jnn9_9hC48c

View File

@ -1,6 +1,8 @@
// 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.
// When waiting for multiple goroutines to finish,
// you may prefer to use a [WaitGroup](waitgroups).
package main
@ -11,22 +13,22 @@ import "time"
// `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")
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
// Send a value to notify that we're done.
done <- true
// 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)
// 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
// Block until we receive a notification from the
// worker on the channel.
<-done
}

View File

@ -1,2 +1,2 @@
fe3e2ea1a67d0f95ce4cb18f3e8aa16d416de0ce
0DfW-1RMqi
eb022977181884c2ab0f2b69e50311769e67a509
8lmP8beav0p

View File

@ -9,18 +9,18 @@ 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)
// 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" }()
// _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)
// 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)
}

View File

@ -1,2 +1,2 @@
926212c784ab820648906c96f6ab21afbc161526
Kd8B0T_JGK
bRGMAqinovA

View File

@ -11,40 +11,40 @@ import "fmt"
// 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)
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 `close`d 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
}
}
}()
// 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 `close`d 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")
// 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](channel-synchronization) approach
// we saw earlier.
<-done
// We await the worker using the
// [synchronization](channel-synchronization) approach
// we saw earlier.
<-done
}

View File

@ -1,2 +1,2 @@
5205898a520533e46ea24c849848d19ebc2d08a9
eFZ2SeKswH
mkz69rVMHs6

View File

@ -12,29 +12,29 @@ import "fmt"
// returned function _closes over_ the variable `i` to
// form a closure.
func intSeq() func() int {
i := 0
return func() int {
i += 1
return i
}
i := 0
return func() int {
i++
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()
// 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())
// 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())
// To confirm that the state is unique to that
// particular function, create and test a new one.
newInts := intSeq()
fmt.Println(newInts())
}

View File

@ -1,2 +1,2 @@
2e062d01989caada16c4b22ff6a35cd58e4eb819
gQtEWkhWyp
e304df67e760dda93ffe434aca58aea4a6c94f19
zb93qzV6iN3

View File

@ -21,91 +21,91 @@ package main
import "strings"
import "fmt"
// Returns the first index of the target string `t`, or
// Index 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
for i, v := range vs {
if v == t {
return i
}
}
return -1
}
// Returns `true` if the target string t is in the
// Include returns `true` if the target string t is in the
// slice.
func Include(vs []string, t string) bool {
return Index(vs, t) >= 0
return Index(vs, t) >= 0
}
// Returns `true` if one of the strings in the slice
// Any 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
for _, v := range vs {
if f(v) {
return true
}
}
return false
}
// Returns `true` if all of the strings in the slice
// All 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
for _, v := range vs {
if !f(v) {
return false
}
}
return true
}
// Returns a new slice containing all strings in the
// Filter 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
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
// Map 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
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"}
// Here we try out our various collection functions.
var strs = []string{"peach", "apple", "pear", "plum"}
fmt.Println(Index(strs, "pear"))
fmt.Println(Index(strs, "pear"))
fmt.Println(Include(strs, "grape"))
fmt.Println(Include(strs, "grape"))
fmt.Println(Any(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
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(All(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
fmt.Println(Filter(strs, func(v string) bool {
return strings.Contains(v, "e")
}))
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))
// The above examples all used anonymous functions,
// but you can also use named functions of the correct
// type.
fmt.Println(Map(strs, strings.ToUpper))
}

View File

@ -1,2 +1,2 @@
ed54b3fc0512ccace0f3d0b74975c9bcd2e7a8a2
3PNdke3Wia
d961fc0e0074aed46cfd1516efdadea78781af56
BJB_npWH516

View File

@ -10,17 +10,17 @@ 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:]
// `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]
// You can get individual args with normal indexing.
arg := os.Args[3]
fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg)
fmt.Println(arg)
fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg)
fmt.Println(arg)
}

View File

@ -1,2 +1,2 @@
41c970a1ef29ad2a05307e6c783ff52ab80eaccd
44uyYt_TRl
6pFdjf800jj

View File

@ -13,37 +13,37 @@ 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")
// 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")
// 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")
// 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()
// 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 pointers 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())
// Here we'll just dump out the parsed options and
// any trailing positional arguments. Note that we
// need to dereference the pointers 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())
}

View File

@ -1,2 +1,2 @@
e2ba0461c090789168c712cc7ed0f66aab09a8c8
NASEOq2R3n
klFR5DitrCy

View File

@ -54,6 +54,3 @@ $ ./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.

View File

@ -0,0 +1,57 @@
// Some command-line tools, like the `go` tool or `git`
// have many *subcommands*, each with its own set of
// flags. For example, `go build` and `go get` are two
// different subcommands of the `go` tool.
// The `flag` package lets us easily define simple
// subcommands that have their own flags.
package main
import (
"flag"
"fmt"
"os"
)
func main() {
// We declare a subcommand using the `NewFlagSet`
// function, and proceed to define new flags specific
// for this subcommand.
fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)
fooEnable := fooCmd.Bool("enable", false, "enable")
fooName := fooCmd.String("name", "", "name")
// For a different subcommand we can define different
// supported flags.
barCmd := flag.NewFlagSet("bar", flag.ExitOnError)
barLevel := barCmd.Int("level", 0, "level")
// The subcommand is expected as the first argument
// to the program.
if len(os.Args) < 2 {
fmt.Println("expected 'foo' or 'bar' subcommands")
os.Exit(1)
}
// Check which subcommand is invoked.
switch os.Args[1] {
// For every subcommand, we parse its own flags and
// have access to trailing positional arguments.
case "foo":
fooCmd.Parse(os.Args[2:])
fmt.Println("subcommand 'foo'")
fmt.Println(" enable:", *fooEnable)
fmt.Println(" name:", *fooName)
fmt.Println(" tail:", fooCmd.Args())
case "bar":
barCmd.Parse(os.Args[2:])
fmt.Println("subcommand 'bar'")
fmt.Println(" level:", *barLevel)
fmt.Println(" tail:", barCmd.Args())
default:
fmt.Println("expected 'foo' or 'bar' subcommands")
os.Exit(1)
}
}

View File

@ -0,0 +1,2 @@
5a0ec258e4992e9b93b11d48f2f249092ff3db66
gtgSAg76N4I

View File

@ -0,0 +1,24 @@
$ go build command-line-subcommands.go
# First invoke the foo subcommand.
$ ./command-line-subcommands foo -enable -name=joe a1 a2
subcommand 'foo'
enable: true
name: joe
tail: [a1 a2]
# Now try bar.
$ ./command-line-subcommands bar -level 8 a1
subcommand 'bar'
level: 8
tail: [a1]
# But bar won't accept foo's flags.
$ ./command-line-subcommands bar -enable a1
flag provided but not defined: -enable
Usage of bar:
-level int
level
# Next we'll look at environment variables, another common
# way to parameterize programs.

View File

@ -10,24 +10,24 @@ import "math"
const s string = "constant"
func main() {
fmt.Println(s)
fmt.Println(s)
// A `const` statement can appear anywhere a `var`
// statement can.
const n = 500000000
// 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)
// 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 numeric constant has no type until it's given
// one, such as by an explicit conversion.
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))
// 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))
}

View File

@ -1,2 +1,2 @@
3de4f16f1ed032378268411b2173b95e8000305d
T5sj0eINnp
2f2ec3a5ff4eef280199da1908eed261346fb40e
VhP0f8moZd3

View File

@ -13,32 +13,38 @@ import "os"
// 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)
// 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
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")
fmt.Println("writing")
fmt.Fprintln(f, "data")
}
func closeFile(f *os.File) {
fmt.Println("closing")
f.Close()
fmt.Println("closing")
err := f.Close()
// It's important to check for errors when closing a
// file, even in a deferred function.
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

View File

@ -1,2 +1,2 @@
570699fc50a1d39e9d0ad6a4461aef3248b080e1
9aoHwzHcAo
fadbe9c05bb42db672316ba19adf3c2189c7b3f5
OrCaBiCrTKq

View File

@ -0,0 +1,95 @@
// Go has several useful functions for working with
// *directories* in the file system.
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
// Create a new sub-directory in the current working
// directory.
err := os.Mkdir("subdir", 0755)
check(err)
// When creating temporary directories, it's good
// practice to `defer` their removal. `os.RemoveAll`
// will delete a whole directory tree (similarly to
// `rm -rf`).
defer os.RemoveAll("subdir")
// Helper function to create a new empty file.
createEmptyFile := func(name string) {
d := []byte("")
check(ioutil.WriteFile(name, d, 0644))
}
createEmptyFile("subdir/file1")
// We can create a hierarchy of directories, including
// parents with `MkdirAll`. This is similar to the
// command-line `mkdir -p`.
err = os.MkdirAll("subdir/parent/child", 0755)
check(err)
createEmptyFile("subdir/parent/file2")
createEmptyFile("subdir/parent/file3")
createEmptyFile("subdir/parent/child/file4")
// `ReadDir` lists directory contents, returning a
// slice of `os.FileInfo` objects.
c, err := ioutil.ReadDir("subdir/parent")
check(err)
fmt.Println("Listing subdir/parent")
for _, entry := range c {
fmt.Println(" ", entry.Name(), entry.IsDir())
}
// `Chdir` lets us change the current working directory,
// similarly to `cd`.
err = os.Chdir("subdir/parent/child")
check(err)
// Now we'll see the contents of `subdir/parent/child`
// when listing the *current* directory.
c, err = ioutil.ReadDir(".")
check(err)
fmt.Println("Listing subdir/parent/child")
for _, entry := range c {
fmt.Println(" ", entry.Name(), entry.IsDir())
}
// `cd` back to where we started.
err = os.Chdir("../../..")
check(err)
// We can also visit a directory *recursively*,
// including all its sub-directories. `Walk` accepts
// a callback function to handle every file or
// directory visited.
fmt.Println("Visiting subdir")
err = filepath.Walk("subdir", visit)
}
// `visit` is called for every file or directory found
// recursively by `filepath.Walk`.
func visit(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Println(" ", p, info.IsDir())
return nil
}

View File

@ -0,0 +1,2 @@
83f67db91816b4544072d0a4d099111a21c60723
-7kWq0PmATF

View File

@ -0,0 +1,15 @@
$ go run directories.go
Listing subdir/parent
child true
file2 false
file3 false
Listing subdir/parent/child
file4 false
Visiting subdir
subdir true
subdir/file1 false
subdir/parent true
subdir/parent/child true
subdir/parent/child/file4 false
subdir/parent/file2 false
subdir/parent/file3 false

View File

@ -11,21 +11,21 @@ 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"))
// 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])
}
// 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])
}
}

View File

@ -1,2 +1,2 @@
4d0832c5a1ddd4e95474791e8802c15452358214
kfqLhpmEpw
CZJ4R_uu6Uu

View File

@ -10,24 +10,24 @@ 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)
// 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
// divide from nanoseconds.
millis := nanos / 1000000
fmt.Println(secs)
fmt.Println(millis)
fmt.Println(nanos)
// Note that there is no `UnixMillis`, so to get the
// milliseconds since epoch you'll need to manually
// divide 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))
// 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))
}

View File

@ -1,2 +1,2 @@
61a498229c8878a97d729cfdd215e5f3960f87ac
GP_zEjhlWk
eN1Qv2ATB-C

View File

@ -15,17 +15,17 @@ 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 {
if arg == 42 {
// `errors.New` constructs a basic `error` value
// with the given error message.
return -1, errors.New("can't work with 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
// 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 `error`s by
@ -33,53 +33,53 @@ func f1(arg int) (int, error) {
// variant on the example above that uses a custom type
// to explicitly represent an argument error.
type argError struct {
arg int
prob string
arg int
prob string
}
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
if arg == 42 {
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
// 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)
}
}
// 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)
}
// 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)
}
}

View File

@ -1,2 +1,2 @@
07cffb3d4e37162ab7e9e0a192561ddc8042b81a
BmDQXkPPTk
210ba0f8196006c0380acaec01655816848ef168
mP_ZR1qjUvA

View File

@ -16,33 +16,33 @@ import "os/exec"
func main() {
// For our example we'll exec `ls`. Go requires an
// absolute 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)
}
// For our example we'll exec `ls`. Go requires an
// absolute 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. Note that the first argument should
// be the program name.
args := []string{"ls", "-a", "-l", "-h"}
// `Exec` requires arguments in slice form (as
// apposed to one big string). We'll give `ls` a few
// common arguments. Note that the first argument should
// be the program name.
args := []string{"ls", "-a", "-l", "-h"}
// `Exec` also needs a set of [environment variables](environment-variables)
// to use. Here we just provide our current
// environment.
env := os.Environ()
// `Exec` also needs a set of [environment variables](environment-variables)
// to use. Here we just provide our current
// environment.
env := os.Environ()
// Here's the actual `syscall.Exec` call. If this call is
// successful, 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)
}
// Here's the actual `syscall.Exec` call. If this call is
// successful, 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)
}
}

View File

@ -1,2 +1,2 @@
b527bbb76a42dd4bae541b73a7377b7e83e79905
neqdJ51KLN
bf11ADw-2Ho

View File

@ -8,12 +8,12 @@ import "os"
func main() {
// `defer`s will _not_ be run when using `os.Exit`, so
// this `fmt.Println` will never be called.
defer fmt.Println("!")
// `defer`s 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)
// Exit with status 3.
os.Exit(3)
}
// Note that unlike e.g. C, Go does not use an integer

View File

@ -1,2 +1,2 @@
dc0bb3eaafa045d6aa05e88aff39322a1ccf822e
CDiAh9SXRM
vDaM0-MGJ_k

View File

@ -0,0 +1,64 @@
// The `filepath` package provides functions to parse
// and construct *file paths* in a way that is portable
// between operating systems; `dir/file` on Linux vs.
// `dir\file` on Windows, for example.
package main
import (
"fmt"
"path/filepath"
"strings"
)
func main() {
// `Join` should be used to construct paths in a
// portable way. It takes any number of arguments
// and constructs a hierarchical path from them.
p := filepath.Join("dir1", "dir2", "filename")
fmt.Println("p:", p)
// You should always use `Join` instead of
// concatenating `/`s or `\`s manually. In addition
// to providing portability, `Join` will also
// normalize paths by removing superfluous separators
// and directory changes.
fmt.Println(filepath.Join("dir1//", "filename"))
fmt.Println(filepath.Join("dir1/../dir1", "filename"))
// `Dir` and `Base` can be used to split a path to the
// directory and the file. Alternatively, `Split` will
// return both in the same call.
fmt.Println("Dir(p):", filepath.Dir(p))
fmt.Println("Base(p):", filepath.Base(p))
// We can check whether a path is absolute.
fmt.Println(filepath.IsAbs("dir/file"))
fmt.Println(filepath.IsAbs("/dir/file"))
filename := "config.json"
// Some file names have extensions following a dot. We
// can split the extension out of such names with `Ext`.
ext := filepath.Ext(filename)
fmt.Println(ext)
// To find the file's name with the extension removed,
// use `strings.TrimSuffix`.
fmt.Println(strings.TrimSuffix(filename, ext))
// `Rel` finds a relative path between a *base* and a
// *target*. It returns an error if the target cannot
// be made relative to base.
rel, err := filepath.Rel("a/b", "a/b/t/file")
if err != nil {
panic(err)
}
fmt.Println(rel)
rel, err = filepath.Rel("a/b", "a/c/t/file")
if err != nil {
panic(err)
}
fmt.Println(rel)
}

View File

@ -0,0 +1,2 @@
1215302b9e59ee9dee21dcd3c47d5f6c672fb058
QIitbMNiFRx

View File

@ -0,0 +1,12 @@
$ go run file-paths.go
p: dir1/dir2/filename
dir1/filename
dir1/filename
Dir(p): dir1/dir2
Base(p): filename
false
true
.json
config
t/file
../c/t/file

View File

@ -7,32 +7,32 @@ import "fmt"
func main() {
// The most basic type, with a single condition.
i := 1
for i <= 3 {
fmt.Println(i)
i = i + 1
}
// 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)
}
// 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
}
// `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
}
// You can also `continue` to the next iteration of
// the loop.
for n := 0; n <= 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
// You can also `continue` to the next iteration of
// the loop.
for n := 0; n <= 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
}

View File

@ -1,2 +1,2 @@
33056d6b36f9894fb6359c9cf2ef8725bbdafa19
KNLLSX4Io_
lGYfUJwiGfi

View File

@ -9,10 +9,10 @@ import "fmt"
// 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
// Go requires explicit returns, i.e. it won't
// automatically return the value of the last
// expression.
return a + b
}
// When you have multiple consecutive parameters of
@ -20,16 +20,16 @@ func plus(a int, b int) int {
// like-typed parameters up to the final parameter that
// declares the type.
func plusPlus(a, b, c int) int {
return a + b + c
return a + b + c
}
func main() {
// Call a function just as you'd expect, with
// `name(args)`.
res := plus(1, 2)
fmt.Println("1+2 =", res)
// Call a function just as you'd expect, with
// `name(args)`.
res := plus(1, 2)
fmt.Println("1+2 =", res)
res = plusPlus(1, 2, 3)
fmt.Println("1+2+3 =", res)
res = plusPlus(1, 2, 3)
fmt.Println("1+2+3 =", res)
}

View File

@ -1,2 +1,2 @@
ae669923c20e5ebf4a7b4b11b8fdf2972accf9e2
9Nky-Dn49f
hzGUvK6iJNm

View File

@ -5,34 +5,33 @@ package main
import "fmt"
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
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")
// 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")
// 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")
// You can also start a goroutine for an anonymous
// function call.
go func(msg string) {
fmt.Println(msg)
}("going")
// Our two function calls 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")
// Our two function calls are running asynchronously in
// separate goroutines now, so execution falls through
// to here. This `Scanln` requires we press a key
// before the program exits.
fmt.Scanln()
fmt.Println("done")
}

View File

@ -1,2 +1,2 @@
a847131d7f112172f9d5509fd3cf31aefb6d710e
RW_RSAHfj-
bfdaa0c8104c1257e6fea102fd26d476a3e8c14e
6Y8t3Yxd1LD

View File

@ -1,6 +1,6 @@
# 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
# two goroutines. This interleaving reflects the
# goroutines being run concurrently by the Go runtime.
$ go run goroutines.go
direct : 0

View File

@ -5,5 +5,5 @@ package main
import "fmt"
func main() {
fmt.Println("hello world")
fmt.Println("hello world")
}

View File

@ -1,2 +1,2 @@
c98395a44701add5bf84e2f3a63e300fc1bc4bfe
2C7wwJ6nxG
mp1ENMU6ZYu

View File

@ -0,0 +1,38 @@
// The Go standard library comes with excellent support
// for HTTP clients and servers in the `net/http`
// package. In this example we'll use it to issue simple
// HTTP requests.
package main
import (
"bufio"
"fmt"
"net/http"
)
func main() {
// Issue an HTTP GET request to a server. `http.Get` is a
// convenient shortcut around creating an `http.Client`
// object and calling its `Get` method; it uses the
// `http.DefaultClient` object which has useful default
// settings.
resp, err := http.Get("http://gobyexample.com")
if err != nil {
panic(err)
}
defer resp.Body.Close()
// Print the HTTP response status.
fmt.Println("Response status:", resp.Status)
// Print the first 5 lines of the response body.
scanner := bufio.NewScanner(resp.Body)
for i := 0; scanner.Scan() && i < 5; i++ {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
}

View File

@ -0,0 +1,2 @@
ec8fd69aa19e54a7ea05d2a911f09d3a98f0396c
VxYIifr_UuH

View File

@ -0,0 +1,7 @@
$ go run http-clients.go
Response status: 200 OK
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Go by Example</title>

View File

@ -0,0 +1,50 @@
// Writing a basic HTTP server is easy using the
// `net/http` package.
package main
import (
"fmt"
"net/http"
)
// A fundamental concept in `net/http` servers is
// *handlers*. A handler is an object implementing the
// `http.Handler` interface. A common way to write
// a handler is by using the `http.HandlerFunc` adapter
// on functions with the appropriate signature.
func hello(w http.ResponseWriter, req *http.Request) {
// Functions serving as handlers take a
// `http.ResponseWriter` and a `http.Request` as
// arguments. The response writer is used to fill in the
// HTTP response. Here our simple response is just
// "hello\n".
fmt.Fprintf(w, "hello\n")
}
func headers(w http.ResponseWriter, req *http.Request) {
// This handler does something a little more
// sophisticated by reading all the HTTP request
// headers and echoing them into the response body.
for name, headers := range req.Header {
for _, h := range headers {
fmt.Fprintf(w, "%v: %v\n", name, h)
}
}
}
func main() {
// We register our handlers on server routes using the
// `http.HandleFunc` convenience function. It sets up
// the *default router* in the `net/http` package and
// takes a function as an argument.
http.HandleFunc("/hello", hello)
http.HandleFunc("/headers", headers)
// Finally, we call the `ListenAndServe` with the port
// and a handler. `nil` tells it to use the default
// router we've just set up.
http.ListenAndServe(":8090", nil)
}

View File

@ -0,0 +1,2 @@
a4e8d30b7a6f3a6abd96b916d81ce5930bad94f9
lNuS9ysZmxH

View File

@ -0,0 +1,6 @@
# Run the server in the background.
$ go run http-servers.go &
# Access the `/hello` route.
$ curl localhost:8090/hello
hello

View File

@ -7,28 +7,28 @@ import "fmt"
func main() {
// Here's a basic example.
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
// 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")
}
// You can have an `if` statement without an else.
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
// A statement can precede 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")
}
// A statement can precede 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

View File

@ -1,2 +1,2 @@
89b78f3378e1a574ddfd0260a0404a962852eff8
g-aqMz0Ivf
p6-WKTqEks4

View File

@ -8,35 +8,35 @@ import "math"
// Here's a basic interface for geometric shapes.
type geometry interface {
area() float64
perim() float64
area() float64
perim() float64
}
// For our example we'll implement this interface on
// `rect` and `circle` types.
type rect struct {
width, height float64
width, height float64
}
type circle struct {
radius float64
radius float64
}
// To implement an interface in Go, we just need to
// implement all the methods in the interface. Here we
// implement `geometry` on `rect`s.
func (r rect) area() float64 {
return r.width * r.height
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
return 2*r.width + 2*r.height
}
// The implementation for `circle`s.
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
return 2 * math.Pi * c.radius
}
// If a variable has an interface type, then we can call
@ -44,19 +44,19 @@ func (c circle) perim() float64 {
// 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())
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
r := rect{width: 3, height: 4}
c := circle{radius: 5}
// The `circle` and `rect` struct types both
// implement the `geometry` interface so we can use
// instances of
// these structs as arguments to `measure`.
measure(r)
measure(c)
// The `circle` and `rect` struct types both
// implement the `geometry` interface so we can use
// instances of
// these structs as arguments to `measure`.
measure(r)
measure(c)
}

View File

@ -1,2 +1,2 @@
3547b935d1e0322c0fb696726c27cae53a275e0a
313UebA3rD
0EwsqIn3TTi

View File

@ -10,110 +10,110 @@ 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 response1 struct {
Page int
Fruits []string
}
type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
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))
// 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))
intB, _ := json.Marshal(1)
fmt.Println(string(intB))
fltB, _ := json.Marshal(2.34)
fmt.Println(string(fltB))
fltB, _ := json.Marshal(2.34)
fmt.Println(string(fltB))
strB, _ := json.Marshal("gopher")
fmt.Println(string(strB))
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))
// 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))
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))
// 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))
// 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.13,"strs":["a","b"]}`)
// Now let's look at decoding JSON data into Go
// values. Here's an example for a generic data
// structure.
byt := []byte(`{"num":6.13,"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{}
// 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)
// 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)
// In order to use the values in the decoded map,
// we'll need to convert them to their appropriate type.
// For example here we convert 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)
// Accessing nested data requires a series of
// conversions.
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])
// 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.Writer`s like
// `os.Stdout` or even HTTP response bodies.
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
// 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.Writer`s like
// `os.Stdout` or even HTTP response bodies.
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d)
}

View File

@ -1,2 +1,2 @@
dee52e022a957b97c53fb2d2835653ef507502be
WxRgpycMaH
d4dc2281f64061f077d8f1e9687538f41a339b25
xC6SHbzGBZC

View File

@ -9,33 +9,33 @@
package main
import (
"bufio"
"fmt"
"os"
"strings"
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// Wrapping the unbuffered `os.Stdin` with a buffered
// scanner gives us a convenient `Scan` method that
// advances the scanner to the next token; which is
// the next line in the default scanner.
scanner := bufio.NewScanner(os.Stdin)
// Wrapping the unbuffered `os.Stdin` with a buffered
// scanner gives us a convenient `Scan` method that
// advances the scanner to the next token; which is
// the next line in the default scanner.
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
// `Text` returns the current token, here the next line,
// from the input.
ucl := strings.ToUpper(scanner.Text())
for scanner.Scan() {
// `Text` returns the current token, here the next line,
// from the input.
ucl := strings.ToUpper(scanner.Text())
// Write out the uppercased line.
fmt.Println(ucl)
}
// Write out the uppercased line.
fmt.Println(ucl)
}
// Check for errors during `Scan`. End of file is
// expected and not reported by `Scan` as an error.
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
// Check for errors during `Scan`. End of file is
// expected and not reported by `Scan` as an error.
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
}

View File

@ -1,2 +1,2 @@
87f4a67edf741979f8ff6da85947aa177547f9ef
mpYwOHj2ma
hnaOIaQAjKF

View File

@ -7,44 +7,44 @@ import "fmt"
func main() {
// To create an empty map, use the builtin `make`:
// `make(map[key-type]val-type)`.
m := make(map[string]int)
// 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
// 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)
// Printing a map with e.g. `fmt.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)
// 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 `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 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 indicates 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 `""`. Here we didn't need the value
// itself, so we ignored it with the _blank identifier_
// `_`.
_, prs := m["k2"]
fmt.Println("prs:", prs)
// The optional second return value when getting a
// value from a map indicates if the key was present
// in the map. This can be used to disambiguate
// between missing keys and keys with zero values
// like `0` or `""`. Here we didn't need the value
// itself, so we ignored it with the _blank identifier_
// `_`.
_, 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)
// 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)
}

View File

@ -1,2 +1,2 @@
2895d63b87f88ab374256c12dd1539cf7b070b77
E6cGoiKqka
3e39d07e3f80ecbac558c6fb8baee2a5f914cf97
U67R66Oab8r

View File

@ -6,4 +6,4 @@ v1: 7
len: 2
map: map[k1:7]
prs: false
map: map[foo:1 bar:2]
map: map[bar:2 foo:1]

View File

@ -5,33 +5,33 @@ package main
import "fmt"
type rect struct {
width, height int
width, height int
}
// This `area` method has a _receiver type_ of `*rect`.
func (r *rect) area() int {
return r.width * r.height
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
return 2*r.width + 2*r.height
}
func main() {
r := rect{width: 10, height: 5}
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())
// 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 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())
}

View File

@ -1,2 +1,2 @@
24cfb9ad45e43c2d49163149bc55925a4e1b3c7a
254m_9Yjwa
ffMb0txGnYB

View File

@ -9,19 +9,19 @@ import "fmt"
// The `(int, int)` in this function signature shows that
// the function returns 2 `int`s.
func vals() (int, int) {
return 3, 7
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)
// 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)
// If you only want a subset of the returned values,
// use the blank identifier `_`.
_, c := vals()
fmt.Println(c)
}

View File

@ -1,2 +1,2 @@
5063ce3d3c70c6bd70f4b709de24bb93d0f24e0c
chwFmr5dG1
FZoIB5LXQGZ

View File

@ -1,85 +1,85 @@
// In the previous example we saw how to manage simple
// counter state using [atomic operations](atomic-counters).
// For more complex state we can use a _[mutex](http://en.wikipedia.org/wiki/Mutual_exclusion)_
// For more complex state we can use a <em>[mutex](http://en.wikipedia.org/wiki/Mutual_exclusion)</em>
// to safely access data across multiple goroutines.
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func main() {
// For our example the `state` will be a map.
var state = make(map[int]int)
// 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{}
// This `mutex` will synchronize access to `state`.
var mutex = &sync.Mutex{}
// We'll keep track of how many read and write
// operations we do.
var readOps uint64 = 0
var writeOps uint64 = 0
// We'll keep track of how many read and write
// operations we do.
var readOps uint64
var writeOps uint64
// Here we start 100 goroutines to execute repeated
// reads against the state, once per millisecond in
// each goroutine.
for r := 0; r < 100; r++ {
go func() {
total := 0
for {
// Here we start 100 goroutines to execute repeated
// reads against the state, once per millisecond in
// each goroutine.
for r := 0; r < 100; r++ {
go func() {
total := 0
for {
// For each read we pick a key to access,
// `Lock()` the `mutex` to ensure
// exclusive access to the `state`, read
// the value at the chosen key,
// `Unlock()` the mutex, and increment
// the `readOps` count.
key := rand.Intn(5)
mutex.Lock()
total += state[key]
mutex.Unlock()
atomic.AddUint64(&readOps, 1)
// For each read we pick a key to access,
// `Lock()` the `mutex` to ensure
// exclusive access to the `state`, read
// the value at the chosen key,
// `Unlock()` the mutex, and increment
// the `readOps` count.
key := rand.Intn(5)
mutex.Lock()
total += state[key]
mutex.Unlock()
atomic.AddUint64(&readOps, 1)
// Wait a bit between reads.
time.Sleep(time.Millisecond)
}
}()
}
// Wait a bit between reads.
time.Sleep(time.Millisecond)
}
}()
}
// We'll also start 10 goroutines to simulate writes,
// using the same pattern we did for reads.
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// We'll also start 10 goroutines to simulate writes,
// using the same pattern we did for reads.
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// Let the 10 goroutines work on the `state` and
// `mutex` for a second.
time.Sleep(time.Second)
// Let the 10 goroutines work on the `state` and
// `mutex` for a second.
time.Sleep(time.Second)
// Take and report final operation counts.
readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal)
// Take and report final operation counts.
readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal)
// With a final lock of `state`, show how it ended up.
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()
// With a final lock of `state`, show how it ended up.
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()
}

View File

@ -1,2 +1,2 @@
e82356cbb37143862b0a9bbc68856f4b272c4918
a9Wky7k-Bw
ca257d9594a6219d5803193132e999a32dc8c856
IRewFKz2OPN

View File

@ -8,39 +8,42 @@ package main
import "fmt"
func main() {
messages := make(chan string)
signals := make(chan bool)
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")
}
// 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")
}
// A non-blocking send works similarly. Here `msg`
// cannot be sent to the `messages` channel, because
// the channel has no buffer and there is no receiver.
// Therefore the `default` case is selected.
msg := "hi"
select {
case messages <- msg:
fmt.Println("sent message", msg)
default:
fmt.Println("no message sent")
}
// We can use multiple `case`s 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")
}
// We can use multiple `case`s 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")
}
}

View File

@ -1,2 +1,2 @@
119ced4df4f79795b163483b6abfd855e76ef577
M972dltae2
a6e0a8bb87153c7ed0de4996172f7ad5d89c6814
n5ttmOsMrrJ

View File

@ -10,31 +10,31 @@ 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)
// 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)
// 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)
// `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)
// 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)
// `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)
// Parse functions return an error on bad input.
_, e := strconv.Atoi("wat")
fmt.Println(e)
}

View File

@ -1,2 +1,2 @@
0d2155e9863a73c098d44637e92403d7f5e8e965
N90EppECFk
NZh4LjhguvN

View File

@ -9,17 +9,17 @@ 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")
// 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
// `panic`king if we get an unexpected error when creating a new file.
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
// 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
// `panic`king if we get an unexpected error when creating a new file.
_, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}

View File

@ -1,2 +1,2 @@
91639bbcfcc6ed088295a9ee6b1c36ab35ae402a
c86oXzfQOt
91HXbZZZopt

View File

@ -12,7 +12,7 @@ import "fmt"
// value. `zeroval` will get a copy of `ival` distinct
// from the one in the calling function.
func zeroval(ival int) {
ival = 0
ival = 0
}
// `zeroptr` in contrast has an `*int` parameter, meaning
@ -22,21 +22,21 @@ func zeroval(ival int) {
// Assigning a value to a dereferenced pointer changes the
// value at the referenced address.
func zeroptr(iptr *int) {
*iptr = 0
*iptr = 0
}
func main() {
i := 1
fmt.Println("initial:", i)
i := 1
fmt.Println("initial:", i)
zeroval(i)
fmt.Println("zeroval:", 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)
// 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)
// Pointers can be printed too.
fmt.Println("pointer:", &i)
}

View File

@ -1,2 +1,2 @@
85cff3345d2f22b65a5d54eb8f7aa8f508f27887
KdE4TBbUL2
fnQkHp4hriG

View File

@ -10,45 +10,45 @@ 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()
// 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())
// `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()
// 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()
// The default number generator is deterministic, so it'll
// produce the same sequence of numbers each time by default.
// To produce varying sequences, give it a seed that changes.
// Note that this is not safe to use for random numbers you
// intend to be secret, use `crypto/rand` for those.
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
// The default number generator is deterministic, so it'll
// produce the same sequence of numbers each time by default.
// To produce varying sequences, give it a seed that changes.
// Note that this is not safe to use for random numbers you
// intend to be secret, use `crypto/rand` for those.
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
// Call the resulting `rand.Rand` just like the
// functions on the `rand` package.
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
// Call the resulting `rand.Rand` just like the
// functions on the `rand` package.
fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100))
fmt.Println()
// If you seed a source with the same number, it
// produces the same sequence of random numbers.
s2 := rand.NewSource(42)
r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
s3 := rand.NewSource(42)
r3 := rand.New(s3)
fmt.Print(r3.Intn(100), ",")
fmt.Print(r3.Intn(100))
// 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()
s3 := rand.NewSource(42)
r3 := rand.New(s3)
fmt.Print(r3.Intn(100), ",")
fmt.Print(r3.Intn(100))
}

View File

@ -1,2 +1,2 @@
8e97de760147b061dd09939db294c892211b6b80
ZdFpbahgC1
jiJaIjxL2sP

View File

@ -9,17 +9,17 @@ 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)
// 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 `close`d the
// channel above, the iteration terminates after
// receiving the 2 elements.
for elem := range queue {
fmt.Println(elem)
}
// This `range` iterates over each element as it's
// received from `queue`. Because we `close`d the
// channel above, the iteration terminates after
// receiving the 2 elements.
for elem := range queue {
fmt.Println(elem)
}
}

View File

@ -1,2 +1,2 @@
8b5d8a77e84c34771c5b14af014ecef3f88b2a6c
I63ge2ISDs
QnARPm-ddFB

Some files were not shown because too many files have changed in this diff Show More