Use tabs as the canonical source indentation in git

Space conversion is done during generation only. Fixes #192
This commit is contained in:
Eli Bendersky 2019-06-01 06:04:32 -07:00 committed by Mark McGranaghan
parent 1699ad1c45
commit 7c160440be
152 changed files with 1929 additions and 1939 deletions

View File

@ -7,36 +7,36 @@ import "fmt"
func main() { func main() {
// Here we create an array `a` that will hold exactly // Here we create an array `a` that will hold exactly
// 5 `int`s. The type of elements and length are both // 5 `int`s. The type of elements and length are both
// part of the array's type. By default an array is // part of the array's type. By default an array is
// zero-valued, which for `int`s means `0`s. // zero-valued, which for `int`s means `0`s.
var a [5]int var a [5]int
fmt.Println("emp:", a) fmt.Println("emp:", a)
// We can set a value at an index using the // We can set a value at an index using the
// `array[index] = value` syntax, and get a value with // `array[index] = value` syntax, and get a value with
// `array[index]`. // `array[index]`.
a[4] = 100 a[4] = 100
fmt.Println("set:", a) fmt.Println("set:", a)
fmt.Println("get:", a[4]) fmt.Println("get:", a[4])
// The builtin `len` returns the length of an array. // The builtin `len` returns the length of an array.
fmt.Println("len:", len(a)) fmt.Println("len:", len(a))
// Use this syntax to declare and initialize an array // Use this syntax to declare and initialize an array
// in one line. // in one line.
b := [5]int{1, 2, 3, 4, 5} b := [5]int{1, 2, 3, 4, 5}
fmt.Println("dcl:", b) fmt.Println("dcl:", b)
// Array types are one-dimensional, but you can // Array types are one-dimensional, but you can
// compose types to build multi-dimensional data // compose types to build multi-dimensional data
// structures. // structures.
var twoD [2][3]int var twoD [2][3]int
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
twoD[i][j] = i + j twoD[i][j] = i + j
} }
} }
fmt.Println("2d: ", twoD) fmt.Println("2d: ", twoD)
} }

View File

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

View File

@ -13,37 +13,37 @@ import "sync/atomic"
func main() { func main() {
// We'll use an unsigned integer to represent our // We'll use an unsigned integer to represent our
// (always-positive) counter. // (always-positive) counter.
var ops uint64 var ops uint64
// To simulate concurrent updates, we'll start 50 // To simulate concurrent updates, we'll start 50
// goroutines that each increment the counter about // goroutines that each increment the counter about
// once a millisecond. // once a millisecond.
for i := 0; i < 50; i++ { for i := 0; i < 50; i++ {
go func() { go func() {
for { for {
// To atomically increment the counter we // To atomically increment the counter we
// use `AddUint64`, giving it the memory // use `AddUint64`, giving it the memory
// address of our `ops` counter with the // address of our `ops` counter with the
// `&` syntax. // `&` syntax.
atomic.AddUint64(&ops, 1) atomic.AddUint64(&ops, 1)
// Wait a bit between increments. // Wait a bit between increments.
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
} }
}() }()
} }
// Wait a second to allow some ops to accumulate. // Wait a second to allow some ops to accumulate.
time.Sleep(time.Second) time.Sleep(time.Second)
// In order to safely use the counter while it's still // In order to safely use the counter while it's still
// being updated by other goroutines, we extract a // being updated by other goroutines, we extract a
// copy of the current value into `opsFinal` via // copy of the current value into `opsFinal` via
// `LoadUint64`. As above we need to give this // `LoadUint64`. As above we need to give this
// function the memory address `&ops` from which to // function the memory address `&ops` from which to
// fetch the value. // fetch the value.
opsFinal := atomic.LoadUint64(&ops) opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal) fmt.Println("ops:", opsFinal)
} }

View File

@ -11,27 +11,27 @@ import "fmt"
func main() { func main() {
// Here's the `string` we'll encode/decode. // Here's the `string` we'll encode/decode.
data := "abc123!?$*&()'-=@~" data := "abc123!?$*&()'-=@~"
// Go supports both standard and URL-compatible // Go supports both standard and URL-compatible
// base64. Here's how to encode using the standard // base64. Here's how to encode using the standard
// encoder. The encoder requires a `[]byte` so we // encoder. The encoder requires a `[]byte` so we
// convert our `string` to that type. // convert our `string` to that type.
sEnc := b64.StdEncoding.EncodeToString([]byte(data)) sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc) fmt.Println(sEnc)
// Decoding may return an error, which you can check // Decoding may return an error, which you can check
// if you don't already know the input to be // if you don't already know the input to be
// well-formed. // well-formed.
sDec, _ := b64.StdEncoding.DecodeString(sEnc) sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec)) fmt.Println(string(sDec))
fmt.Println() fmt.Println()
// This encodes/decodes using a URL-compatible base64 // This encodes/decodes using a URL-compatible base64
// format. // format.
uEnc := b64.URLEncoding.EncodeToString([]byte(data)) uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc) fmt.Println(uEnc)
uDec, _ := b64.URLEncoding.DecodeString(uEnc) uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec)) fmt.Println(string(uDec))
} }

View File

@ -11,17 +11,17 @@ import "fmt"
func main() { func main() {
// Here we `make` a channel of strings buffering up to // Here we `make` a channel of strings buffering up to
// 2 values. // 2 values.
messages := make(chan string, 2) messages := make(chan string, 2)
// Because this channel is buffered, we can send these // Because this channel is buffered, we can send these
// values into the channel without a corresponding // values into the channel without a corresponding
// concurrent receive. // concurrent receive.
messages <- "buffered" messages <- "buffered"
messages <- "channel" messages <- "channel"
// Later we can receive these two values as usual. // Later we can receive these two values as usual.
fmt.Println(<-messages) fmt.Println(<-messages)
fmt.Println(<-messages) fmt.Println(<-messages)
} }

View File

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

View File

@ -11,20 +11,20 @@ import "fmt"
// values. It would be a compile-time error to try to // values. It would be a compile-time error to try to
// receive on this channel. // receive on this channel.
func ping(pings chan<- string, msg string) { func ping(pings chan<- string, msg string) {
pings <- msg pings <- msg
} }
// The `pong` function accepts one channel for receives // The `pong` function accepts one channel for receives
// (`pings`) and a second for sends (`pongs`). // (`pings`) and a second for sends (`pongs`).
func pong(pings <-chan string, pongs chan<- string) { func pong(pings <-chan string, pongs chan<- string) {
msg := <-pings msg := <-pings
pongs <- msg pongs <- msg
} }
func main() { func main() {
pings := make(chan string, 1) pings := make(chan string, 1)
pongs := make(chan string, 1) pongs := make(chan string, 1)
ping(pings, "passed message") ping(pings, "passed message")
pong(pings, pongs) pong(pings, pongs)
fmt.Println(<-pongs) fmt.Println(<-pongs)
} }

View File

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

View File

@ -13,22 +13,22 @@ import "time"
// `done` channel will be used to notify another // `done` channel will be used to notify another
// goroutine that this function's work is done. // goroutine that this function's work is done.
func worker(done chan bool) { func worker(done chan bool) {
fmt.Print("working...") fmt.Print("working...")
time.Sleep(time.Second) time.Sleep(time.Second)
fmt.Println("done") fmt.Println("done")
// Send a value to notify that we're done. // Send a value to notify that we're done.
done <- true done <- true
} }
func main() { func main() {
// Start a worker goroutine, giving it the channel to // Start a worker goroutine, giving it the channel to
// notify on. // notify on.
done := make(chan bool, 1) done := make(chan bool, 1)
go worker(done) go worker(done)
// Block until we receive a notification from the // Block until we receive a notification from the
// worker on the channel. // worker on the channel.
<-done <-done
} }

View File

@ -9,18 +9,18 @@ import "fmt"
func main() { func main() {
// Create a new channel with `make(chan val-type)`. // Create a new channel with `make(chan val-type)`.
// Channels are typed by the values they convey. // Channels are typed by the values they convey.
messages := make(chan string) messages := make(chan string)
// _Send_ a value into a channel using the `channel <-` // _Send_ a value into a channel using the `channel <-`
// syntax. Here we send `"ping"` to the `messages` // syntax. Here we send `"ping"` to the `messages`
// channel we made above, from a new goroutine. // channel we made above, from a new goroutine.
go func() { messages <- "ping" }() go func() { messages <- "ping" }()
// The `<-channel` syntax _receives_ a value from the // The `<-channel` syntax _receives_ a value from the
// channel. Here we'll receive the `"ping"` message // channel. Here we'll receive the `"ping"` message
// we sent above and print it out. // we sent above and print it out.
msg := <-messages msg := <-messages
fmt.Println(msg) fmt.Println(msg)
} }

View File

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

View File

@ -11,40 +11,40 @@ import "fmt"
// to a worker goroutine. When we have no more jobs for // to a worker goroutine. When we have no more jobs for
// the worker we'll `close` the `jobs` channel. // the worker we'll `close` the `jobs` channel.
func main() { func main() {
jobs := make(chan int, 5) jobs := make(chan int, 5)
done := make(chan bool) done := make(chan bool)
// Here's the worker goroutine. It repeatedly receives // Here's the worker goroutine. It repeatedly receives
// from `jobs` with `j, more := <-jobs`. In this // from `jobs` with `j, more := <-jobs`. In this
// special 2-value form of receive, the `more` value // special 2-value form of receive, the `more` value
// will be `false` if `jobs` has been `close`d and all // will be `false` if `jobs` has been `close`d and all
// values in the channel have already been received. // values in the channel have already been received.
// We use this to notify on `done` when we've worked // We use this to notify on `done` when we've worked
// all our jobs. // all our jobs.
go func() { go func() {
for { for {
j, more := <-jobs j, more := <-jobs
if more { if more {
fmt.Println("received job", j) fmt.Println("received job", j)
} else { } else {
fmt.Println("received all jobs") fmt.Println("received all jobs")
done <- true done <- true
return return
} }
} }
}() }()
// This sends 3 jobs to the worker over the `jobs` // This sends 3 jobs to the worker over the `jobs`
// channel, then closes it. // channel, then closes it.
for j := 1; j <= 3; j++ { for j := 1; j <= 3; j++ {
jobs <- j jobs <- j
fmt.Println("sent job", j) fmt.Println("sent job", j)
} }
close(jobs) close(jobs)
fmt.Println("sent all jobs") fmt.Println("sent all jobs")
// We await the worker using the // We await the worker using the
// [synchronization](channel-synchronization) approach // [synchronization](channel-synchronization) approach
// we saw earlier. // we saw earlier.
<-done <-done
} }

View File

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

View File

@ -12,29 +12,29 @@ import "fmt"
// returned function _closes over_ the variable `i` to // returned function _closes over_ the variable `i` to
// form a closure. // form a closure.
func intSeq() func() int { func intSeq() func() int {
i := 0 i := 0
return func() int { return func() int {
i++ i++
return i return i
} }
} }
func main() { func main() {
// We call `intSeq`, assigning the result (a function) // We call `intSeq`, assigning the result (a function)
// to `nextInt`. This function value captures its // to `nextInt`. This function value captures its
// own `i` value, which will be updated each time // own `i` value, which will be updated each time
// we call `nextInt`. // we call `nextInt`.
nextInt := intSeq() nextInt := intSeq()
// See the effect of the closure by calling `nextInt` // See the effect of the closure by calling `nextInt`
// a few times. // a few times.
fmt.Println(nextInt()) fmt.Println(nextInt())
fmt.Println(nextInt()) fmt.Println(nextInt())
fmt.Println(nextInt()) fmt.Println(nextInt())
// To confirm that the state is unique to that // To confirm that the state is unique to that
// particular function, create and test a new one. // particular function, create and test a new one.
newInts := intSeq() newInts := intSeq()
fmt.Println(newInts()) fmt.Println(newInts())
} }

View File

@ -24,88 +24,88 @@ import "fmt"
// Index 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. // -1 if no match is found.
func Index(vs []string, t string) int { func Index(vs []string, t string) int {
for i, v := range vs { for i, v := range vs {
if v == t { if v == t {
return i return i
} }
} }
return -1 return -1
} }
// Include returns `true` if the target string t is in the // Include returns `true` if the target string t is in the
// slice. // slice.
func Include(vs []string, t string) bool { func Include(vs []string, t string) bool {
return Index(vs, t) >= 0 return Index(vs, t) >= 0
} }
// Any 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`. // satisfies the predicate `f`.
func Any(vs []string, f func(string) bool) bool { func Any(vs []string, f func(string) bool) bool {
for _, v := range vs { for _, v := range vs {
if f(v) { if f(v) {
return true return true
} }
} }
return false return false
} }
// All 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`. // satisfy the predicate `f`.
func All(vs []string, f func(string) bool) bool { func All(vs []string, f func(string) bool) bool {
for _, v := range vs { for _, v := range vs {
if !f(v) { if !f(v) {
return false return false
} }
} }
return true return true
} }
// Filter 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`. // slice that satisfy the predicate `f`.
func Filter(vs []string, f func(string) bool) []string { func Filter(vs []string, f func(string) bool) []string {
vsf := make([]string, 0) vsf := make([]string, 0)
for _, v := range vs { for _, v := range vs {
if f(v) { if f(v) {
vsf = append(vsf, v) vsf = append(vsf, v)
} }
} }
return vsf return vsf
} }
// Map 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. // the function `f` to each string in the original slice.
func Map(vs []string, f func(string) string) []string { func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs)) vsm := make([]string, len(vs))
for i, v := range vs { for i, v := range vs {
vsm[i] = f(v) vsm[i] = f(v)
} }
return vsm return vsm
} }
func main() { func main() {
// Here we try out our various collection functions. // Here we try out our various collection functions.
var strs = []string{"peach", "apple", "pear", "plum"} 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 { fmt.Println(Any(strs, func(v string) bool {
return strings.HasPrefix(v, "p") return strings.HasPrefix(v, "p")
})) }))
fmt.Println(All(strs, func(v string) bool { fmt.Println(All(strs, func(v string) bool {
return strings.HasPrefix(v, "p") return strings.HasPrefix(v, "p")
})) }))
fmt.Println(Filter(strs, func(v string) bool { fmt.Println(Filter(strs, func(v string) bool {
return strings.Contains(v, "e") return strings.Contains(v, "e")
})) }))
// The above examples all used anonymous functions, // The above examples all used anonymous functions,
// but you can also use named functions of the correct // but you can also use named functions of the correct
// type. // type.
fmt.Println(Map(strs, strings.ToUpper)) fmt.Println(Map(strs, strings.ToUpper))
} }

View File

@ -10,17 +10,17 @@ import "fmt"
func main() { func main() {
// `os.Args` provides access to raw command-line // `os.Args` provides access to raw command-line
// arguments. Note that the first value in this slice // arguments. Note that the first value in this slice
// is the path to the program, and `os.Args[1:]` // is the path to the program, and `os.Args[1:]`
// holds the arguments to the program. // holds the arguments to the program.
argsWithProg := os.Args argsWithProg := os.Args
argsWithoutProg := os.Args[1:] argsWithoutProg := os.Args[1:]
// You can get individual args with normal indexing. // You can get individual args with normal indexing.
arg := os.Args[3] arg := os.Args[3]
fmt.Println(argsWithProg) fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg) fmt.Println(argsWithoutProg)
fmt.Println(arg) fmt.Println(arg)
} }

View File

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

View File

@ -13,37 +13,37 @@ import "fmt"
func main() { func main() {
// Basic flag declarations are available for string, // Basic flag declarations are available for string,
// integer, and boolean options. Here we declare a // integer, and boolean options. Here we declare a
// string flag `word` with a default value `"foo"` // string flag `word` with a default value `"foo"`
// and a short description. This `flag.String` function // and a short description. This `flag.String` function
// returns a string pointer (not a string value); // returns a string pointer (not a string value);
// we'll see how to use this pointer below. // we'll see how to use this pointer below.
wordPtr := flag.String("word", "foo", "a string") wordPtr := flag.String("word", "foo", "a string")
// This declares `numb` and `fork` flags, using a // This declares `numb` and `fork` flags, using a
// similar approach to the `word` flag. // similar approach to the `word` flag.
numbPtr := flag.Int("numb", 42, "an int") numbPtr := flag.Int("numb", 42, "an int")
boolPtr := flag.Bool("fork", false, "a bool") boolPtr := flag.Bool("fork", false, "a bool")
// It's also possible to declare an option that uses an // It's also possible to declare an option that uses an
// existing var declared elsewhere in the program. // existing var declared elsewhere in the program.
// Note that we need to pass in a pointer to the flag // Note that we need to pass in a pointer to the flag
// declaration function. // declaration function.
var svar string var svar string
flag.StringVar(&svar, "svar", "bar", "a string var") flag.StringVar(&svar, "svar", "bar", "a string var")
// Once all flags are declared, call `flag.Parse()` // Once all flags are declared, call `flag.Parse()`
// to execute the command-line parsing. // to execute the command-line parsing.
flag.Parse() flag.Parse()
// Here we'll just dump out the parsed options and // Here we'll just dump out the parsed options and
// any trailing positional arguments. Note that we // any trailing positional arguments. Note that we
// need to dereference the pointers with e.g. `*wordPtr` // need to dereference the pointers with e.g. `*wordPtr`
// to get the actual option values. // to get the actual option values.
fmt.Println("word:", *wordPtr) fmt.Println("word:", *wordPtr)
fmt.Println("numb:", *numbPtr) fmt.Println("numb:", *numbPtr)
fmt.Println("fork:", *boolPtr) fmt.Println("fork:", *boolPtr)
fmt.Println("svar:", svar) fmt.Println("svar:", svar)
fmt.Println("tail:", flag.Args()) fmt.Println("tail:", flag.Args())
} }

View File

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

View File

@ -10,24 +10,24 @@ import "math"
const s string = "constant" const s string = "constant"
func main() { func main() {
fmt.Println(s) fmt.Println(s)
// A `const` statement can appear anywhere a `var` // A `const` statement can appear anywhere a `var`
// statement can. // statement can.
const n = 500000000 const n = 500000000
// Constant expressions perform arithmetic with // Constant expressions perform arithmetic with
// arbitrary precision. // arbitrary precision.
const d = 3e20 / n const d = 3e20 / n
fmt.Println(d) fmt.Println(d)
// A numeric constant has no type until it's given // A numeric constant has no type until it's given
// one, such as by an explicit conversion. // one, such as by an explicit conversion.
fmt.Println(int64(d)) fmt.Println(int64(d))
// A number can be given a type by using it in a // A number can be given a type by using it in a
// context that requires one, such as a variable // context that requires one, such as a variable
// assignment or function call. For example, here // assignment or function call. For example, here
// `math.Sin` expects a `float64`. // `math.Sin` expects a `float64`.
fmt.Println(math.Sin(n)) fmt.Println(math.Sin(n))
} }

View File

@ -13,32 +13,32 @@ import "os"
// do that with `defer`. // do that with `defer`.
func main() { func main() {
// Immediately after getting a file object with // Immediately after getting a file object with
// `createFile`, we defer the closing of that file // `createFile`, we defer the closing of that file
// with `closeFile`. This will be executed at the end // with `closeFile`. This will be executed at the end
// of the enclosing function (`main`), after // of the enclosing function (`main`), after
// `writeFile` has finished. // `writeFile` has finished.
f := createFile("/tmp/defer.txt") f := createFile("/tmp/defer.txt")
defer closeFile(f) defer closeFile(f)
writeFile(f) writeFile(f)
} }
func createFile(p string) *os.File { func createFile(p string) *os.File {
fmt.Println("creating") fmt.Println("creating")
f, err := os.Create(p) f, err := os.Create(p)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return f return f
} }
func writeFile(f *os.File) { func writeFile(f *os.File) {
fmt.Println("writing") fmt.Println("writing")
fmt.Fprintln(f, "data") fmt.Fprintln(f, "data")
} }
func closeFile(f *os.File) { func closeFile(f *os.File) {
fmt.Println("closing") fmt.Println("closing")
f.Close() f.Close()
} }

View File

@ -1,2 +1,2 @@
570699fc50a1d39e9d0ad6a4461aef3248b080e1 570699fc50a1d39e9d0ad6a4461aef3248b080e1
9aoHwzHcAo xPbQ5SGkH2O

View File

@ -11,21 +11,21 @@ import "fmt"
func main() { func main() {
// To set a key/value pair, use `os.Setenv`. To get a // To set a key/value pair, use `os.Setenv`. To get a
// value for a key, use `os.Getenv`. This will return // value for a key, use `os.Getenv`. This will return
// an empty string if the key isn't present in the // an empty string if the key isn't present in the
// environment. // environment.
os.Setenv("FOO", "1") os.Setenv("FOO", "1")
fmt.Println("FOO:", os.Getenv("FOO")) fmt.Println("FOO:", os.Getenv("FOO"))
fmt.Println("BAR:", os.Getenv("BAR")) fmt.Println("BAR:", os.Getenv("BAR"))
// Use `os.Environ` to list all key/value pairs in the // Use `os.Environ` to list all key/value pairs in the
// environment. This returns a slice of strings in the // environment. This returns a slice of strings in the
// form `KEY=value`. You can `strings.Split` them to // form `KEY=value`. You can `strings.Split` them to
// get the key and value. Here we print all the keys. // get the key and value. Here we print all the keys.
fmt.Println() fmt.Println()
for _, e := range os.Environ() { for _, e := range os.Environ() {
pair := strings.Split(e, "=") pair := strings.Split(e, "=")
fmt.Println(pair[0]) fmt.Println(pair[0])
} }
} }

View File

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

View File

@ -10,24 +10,24 @@ import "time"
func main() { func main() {
// Use `time.Now` with `Unix` or `UnixNano` to get // Use `time.Now` with `Unix` or `UnixNano` to get
// elapsed time since the Unix epoch in seconds or // elapsed time since the Unix epoch in seconds or
// nanoseconds, respectively. // nanoseconds, respectively.
now := time.Now() now := time.Now()
secs := now.Unix() secs := now.Unix()
nanos := now.UnixNano() nanos := now.UnixNano()
fmt.Println(now) fmt.Println(now)
// Note that there is no `UnixMillis`, so to get the // Note that there is no `UnixMillis`, so to get the
// milliseconds since epoch you'll need to manually // milliseconds since epoch you'll need to manually
// divide from nanoseconds. // divide from nanoseconds.
millis := nanos / 1000000 millis := nanos / 1000000
fmt.Println(secs) fmt.Println(secs)
fmt.Println(millis) fmt.Println(millis)
fmt.Println(nanos) fmt.Println(nanos)
// You can also convert integer seconds or nanoseconds // You can also convert integer seconds or nanoseconds
// since the epoch into the corresponding `time`. // since the epoch into the corresponding `time`.
fmt.Println(time.Unix(secs, 0)) fmt.Println(time.Unix(secs, 0))
fmt.Println(time.Unix(0, nanos)) fmt.Println(time.Unix(0, nanos))
} }

View File

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

View File

@ -15,17 +15,17 @@ import "fmt"
// By convention, errors are the last return value and // By convention, errors are the last return value and
// have type `error`, a built-in interface. // have type `error`, a built-in interface.
func f1(arg int) (int, error) { func f1(arg int) (int, error) {
if arg == 42 { if arg == 42 {
// `errors.New` constructs a basic `error` value // `errors.New` constructs a basic `error` value
// with the given error message. // with the given error message.
return -1, errors.New("can't work with 42") return -1, errors.New("can't work with 42")
} }
// A `nil` value in the error position indicates that // A `nil` value in the error position indicates that
// there was no error. // there was no error.
return arg + 3, nil return arg + 3, nil
} }
// It's possible to use custom types as `error`s by // 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 // variant on the example above that uses a custom type
// to explicitly represent an argument error. // to explicitly represent an argument error.
type argError struct { type argError struct {
arg int arg int
prob string prob string
} }
func (e *argError) Error() 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) { func f2(arg int) (int, error) {
if arg == 42 { if arg == 42 {
// In this case we use `&argError` syntax to build // In this case we use `&argError` syntax to build
// a new struct, supplying values for the two // a new struct, supplying values for the two
// fields `arg` and `prob`. // fields `arg` and `prob`.
return -1, &argError{arg, "can't work with it"} return -1, &argError{arg, "can't work with it"}
} }
return arg + 3, nil return arg + 3, nil
} }
func main() { func main() {
// The two loops below test out each of our // The two loops below test out each of our
// error-returning functions. Note that the use of an // error-returning functions. Note that the use of an
// inline error check on the `if` line is a common // inline error check on the `if` line is a common
// idiom in Go code. // idiom in Go code.
for _, i := range []int{7, 42} { for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil { if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e) fmt.Println("f1 failed:", e)
} else { } else {
fmt.Println("f1 worked:", r) fmt.Println("f1 worked:", r)
} }
} }
for _, i := range []int{7, 42} { for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil { if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e) fmt.Println("f2 failed:", e)
} else { } else {
fmt.Println("f2 worked:", r) fmt.Println("f2 worked:", r)
} }
} }
// If you want to programmatically use the data in // If you want to programmatically use the data in
// a custom error, you'll need to get the error as an // a custom error, you'll need to get the error as an
// instance of the custom error type via type // instance of the custom error type via type
// assertion. // assertion.
_, e := f2(42) _, e := f2(42)
if ae, ok := e.(*argError); ok { if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg) fmt.Println(ae.arg)
fmt.Println(ae.prob) fmt.Println(ae.prob)
} }
} }

View File

@ -16,33 +16,33 @@ import "os/exec"
func main() { func main() {
// For our example we'll exec `ls`. Go requires an // For our example we'll exec `ls`. Go requires an
// absolute path to the binary we want to execute, so // absolute path to the binary we want to execute, so
// we'll use `exec.LookPath` to find it (probably // we'll use `exec.LookPath` to find it (probably
// `/bin/ls`). // `/bin/ls`).
binary, lookErr := exec.LookPath("ls") binary, lookErr := exec.LookPath("ls")
if lookErr != nil { if lookErr != nil {
panic(lookErr) panic(lookErr)
} }
// `Exec` requires arguments in slice form (as // `Exec` requires arguments in slice form (as
// apposed to one big string). We'll give `ls` a few // apposed to one big string). We'll give `ls` a few
// common arguments. Note that the first argument should // common arguments. Note that the first argument should
// be the program name. // be the program name.
args := []string{"ls", "-a", "-l", "-h"} args := []string{"ls", "-a", "-l", "-h"}
// `Exec` also needs a set of [environment variables](environment-variables) // `Exec` also needs a set of [environment variables](environment-variables)
// to use. Here we just provide our current // to use. Here we just provide our current
// environment. // environment.
env := os.Environ() env := os.Environ()
// Here's the actual `syscall.Exec` call. If this call is // Here's the actual `syscall.Exec` call. If this call is
// successful, the execution of our process will end // successful, the execution of our process will end
// here and be replaced by the `/bin/ls -a -l -h` // here and be replaced by the `/bin/ls -a -l -h`
// process. If there is an error we'll get a return // process. If there is an error we'll get a return
// value. // value.
execErr := syscall.Exec(binary, args, env) execErr := syscall.Exec(binary, args, env)
if execErr != nil { if execErr != nil {
panic(execErr) panic(execErr)
} }
} }

View File

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

View File

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

View File

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

View File

@ -7,32 +7,32 @@ import "fmt"
func main() { func main() {
// The most basic type, with a single condition. // The most basic type, with a single condition.
i := 1 i := 1
for i <= 3 { for i <= 3 {
fmt.Println(i) fmt.Println(i)
i = i + 1 i = i + 1
} }
// A classic initial/condition/after `for` loop. // A classic initial/condition/after `for` loop.
for j := 7; j <= 9; j++ { for j := 7; j <= 9; j++ {
fmt.Println(j) fmt.Println(j)
} }
// `for` without a condition will loop repeatedly // `for` without a condition will loop repeatedly
// until you `break` out of the loop or `return` from // until you `break` out of the loop or `return` from
// the enclosing function. // the enclosing function.
for { for {
fmt.Println("loop") fmt.Println("loop")
break break
} }
// You can also `continue` to the next iteration of // You can also `continue` to the next iteration of
// the loop. // the loop.
for n := 0; n <= 5; n++ { for n := 0; n <= 5; n++ {
if n%2 == 0 { if n%2 == 0 {
continue continue
} }
fmt.Println(n) fmt.Println(n)
} }
} }

View File

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

View File

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

View File

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

View File

@ -5,33 +5,33 @@ package main
import "fmt" import "fmt"
func f(from string) { func f(from string) {
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
fmt.Println(from, ":", i) fmt.Println(from, ":", i)
} }
} }
func main() { func main() {
// Suppose we have a function call `f(s)`. Here's how // Suppose we have a function call `f(s)`. Here's how
// we'd call that in the usual way, running it // we'd call that in the usual way, running it
// synchronously. // synchronously.
f("direct") f("direct")
// To invoke this function in a goroutine, use // To invoke this function in a goroutine, use
// `go f(s)`. This new goroutine will execute // `go f(s)`. This new goroutine will execute
// concurrently with the calling one. // concurrently with the calling one.
go f("goroutine") go f("goroutine")
// You can also start a goroutine for an anonymous // You can also start a goroutine for an anonymous
// function call. // function call.
go func(msg string) { go func(msg string) {
fmt.Println(msg) fmt.Println(msg)
}("going") }("going")
// Our two function calls are running asynchronously in // Our two function calls are running asynchronously in
// separate goroutines now, so execution falls through // separate goroutines now, so execution falls through
// to here. This `Scanln` requires we press a key // to here. This `Scanln` requires we press a key
// before the program exits. // before the program exits.
fmt.Scanln() fmt.Scanln()
fmt.Println("done") fmt.Println("done")
} }

View File

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

View File

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

View File

@ -5,34 +5,34 @@
package main package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"net/http" "net/http"
) )
func main() { func main() {
// Issue an HTTP GET request to a server. `http.Get` is a // Issue an HTTP GET request to a server. `http.Get` is a
// convenient shortcut around creating an `http.Client` // convenient shortcut around creating an `http.Client`
// object and calling its `Get` method; it uses the // object and calling its `Get` method; it uses the
// `http.DefaultClient` object which has useful default // `http.DefaultClient` object which has useful default
// settings. // settings.
resp, err := http.Get("http://gobyexample.com") resp, err := http.Get("http://gobyexample.com")
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer resp.Body.Close() defer resp.Body.Close()
// Print the HTTP response status. // Print the HTTP response status.
fmt.Println("Response status:", resp.Status) fmt.Println("Response status:", resp.Status)
// Print the first 5 lines of the response body. // Print the first 5 lines of the response body.
scanner := bufio.NewScanner(resp.Body) scanner := bufio.NewScanner(resp.Body)
for i := 0; scanner.Scan() && i < 5; i++ { for i := 0; scanner.Scan() && i < 5; i++ {
fmt.Println(scanner.Text()) fmt.Println(scanner.Text())
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
panic(err) panic(err)
} }
} }

View File

@ -7,28 +7,28 @@ import "fmt"
func main() { func main() {
// Here's a basic example. // Here's a basic example.
if 7%2 == 0 { if 7%2 == 0 {
fmt.Println("7 is even") fmt.Println("7 is even")
} else { } else {
fmt.Println("7 is odd") fmt.Println("7 is odd")
} }
// You can have an `if` statement without an else. // You can have an `if` statement without an else.
if 8%4 == 0 { if 8%4 == 0 {
fmt.Println("8 is divisible by 4") fmt.Println("8 is divisible by 4")
} }
// A statement can precede conditionals; any variables // A statement can precede conditionals; any variables
// declared in this statement are available in all // declared in this statement are available in all
// branches. // branches.
if num := 9; num < 0 { if num := 9; num < 0 {
fmt.Println(num, "is negative") fmt.Println(num, "is negative")
} else if num < 10 { } else if num < 10 {
fmt.Println(num, "has 1 digit") fmt.Println(num, "has 1 digit")
} else { } else {
fmt.Println(num, "has multiple digits") fmt.Println(num, "has multiple digits")
} }
} }
// Note that you don't need parentheses around conditions // Note that you don't need parentheses around conditions

View File

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

View File

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

View File

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

View File

@ -11,109 +11,109 @@ import "os"
// We'll use these two structs to demonstrate encoding and // We'll use these two structs to demonstrate encoding and
// decoding of custom types below. // decoding of custom types below.
type response1 struct { type response1 struct {
Page int Page int
Fruits []string Fruits []string
} }
type response2 struct { type response2 struct {
Page int `json:"page"` Page int `json:"page"`
Fruits []string `json:"fruits"` Fruits []string `json:"fruits"`
} }
func main() { func main() {
// First we'll look at encoding basic data types to // First we'll look at encoding basic data types to
// JSON strings. Here are some examples for atomic // JSON strings. Here are some examples for atomic
// values. // values.
bolB, _ := json.Marshal(true) bolB, _ := json.Marshal(true)
fmt.Println(string(bolB)) fmt.Println(string(bolB))
intB, _ := json.Marshal(1) intB, _ := json.Marshal(1)
fmt.Println(string(intB)) fmt.Println(string(intB))
fltB, _ := json.Marshal(2.34) fltB, _ := json.Marshal(2.34)
fmt.Println(string(fltB)) fmt.Println(string(fltB))
strB, _ := json.Marshal("gopher") strB, _ := json.Marshal("gopher")
fmt.Println(string(strB)) fmt.Println(string(strB))
// And here are some for slices and maps, which encode // And here are some for slices and maps, which encode
// to JSON arrays and objects as you'd expect. // to JSON arrays and objects as you'd expect.
slcD := []string{"apple", "peach", "pear"} slcD := []string{"apple", "peach", "pear"}
slcB, _ := json.Marshal(slcD) slcB, _ := json.Marshal(slcD)
fmt.Println(string(slcB)) fmt.Println(string(slcB))
mapD := map[string]int{"apple": 5, "lettuce": 7} mapD := map[string]int{"apple": 5, "lettuce": 7}
mapB, _ := json.Marshal(mapD) mapB, _ := json.Marshal(mapD)
fmt.Println(string(mapB)) fmt.Println(string(mapB))
// The JSON package can automatically encode your // The JSON package can automatically encode your
// custom data types. It will only include exported // custom data types. It will only include exported
// fields in the encoded output and will by default // fields in the encoded output and will by default
// use those names as the JSON keys. // use those names as the JSON keys.
res1D := &response1{ res1D := &response1{
Page: 1, Page: 1,
Fruits: []string{"apple", "peach", "pear"}} Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D) res1B, _ := json.Marshal(res1D)
fmt.Println(string(res1B)) fmt.Println(string(res1B))
// You can use tags on struct field declarations // You can use tags on struct field declarations
// to customize the encoded JSON key names. Check the // to customize the encoded JSON key names. Check the
// definition of `response2` above to see an example // definition of `response2` above to see an example
// of such tags. // of such tags.
res2D := &response2{ res2D := &response2{
Page: 1, Page: 1,
Fruits: []string{"apple", "peach", "pear"}} Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D) res2B, _ := json.Marshal(res2D)
fmt.Println(string(res2B)) fmt.Println(string(res2B))
// Now let's look at decoding JSON data into Go // Now let's look at decoding JSON data into Go
// values. Here's an example for a generic data // values. Here's an example for a generic data
// structure. // structure.
byt := []byte(`{"num":6.13,"strs":["a","b"]}`) byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
// We need to provide a variable where the JSON // We need to provide a variable where the JSON
// package can put the decoded data. This // package can put the decoded data. This
// `map[string]interface{}` will hold a map of strings // `map[string]interface{}` will hold a map of strings
// to arbitrary data types. // to arbitrary data types.
var dat map[string]interface{} var dat map[string]interface{}
// Here's the actual decoding, and a check for // Here's the actual decoding, and a check for
// associated errors. // associated errors.
if err := json.Unmarshal(byt, &dat); err != nil { if err := json.Unmarshal(byt, &dat); err != nil {
panic(err) panic(err)
} }
fmt.Println(dat) fmt.Println(dat)
// In order to use the values in the decoded map, // In order to use the values in the decoded map,
// we'll need to convert them to their appropriate type. // we'll need to convert them to their appropriate type.
// For example here we convert the value in `num` to // For example here we convert the value in `num` to
// the expected `float64` type. // the expected `float64` type.
num := dat["num"].(float64) num := dat["num"].(float64)
fmt.Println(num) fmt.Println(num)
// Accessing nested data requires a series of // Accessing nested data requires a series of
// conversions. // conversions.
strs := dat["strs"].([]interface{}) strs := dat["strs"].([]interface{})
str1 := strs[0].(string) str1 := strs[0].(string)
fmt.Println(str1) fmt.Println(str1)
// We can also decode JSON into custom data types. // We can also decode JSON into custom data types.
// This has the advantages of adding additional // This has the advantages of adding additional
// type-safety to our programs and eliminating the // type-safety to our programs and eliminating the
// need for type assertions when accessing the decoded // need for type assertions when accessing the decoded
// data. // data.
str := `{"page": 1, "fruits": ["apple", "peach"]}` str := `{"page": 1, "fruits": ["apple", "peach"]}`
res := response2{} res := response2{}
json.Unmarshal([]byte(str), &res) json.Unmarshal([]byte(str), &res)
fmt.Println(res) fmt.Println(res)
fmt.Println(res.Fruits[0]) fmt.Println(res.Fruits[0])
// In the examples above we always used bytes and // In the examples above we always used bytes and
// strings as intermediates between the data and // strings as intermediates between the data and
// JSON representation on standard out. We can also // JSON representation on standard out. We can also
// stream JSON encodings directly to `os.Writer`s like // stream JSON encodings directly to `os.Writer`s like
// `os.Stdout` or even HTTP response bodies. // `os.Stdout` or even HTTP response bodies.
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple": 5, "lettuce": 7} d := map[string]int{"apple": 5, "lettuce": 7}
enc.Encode(d) enc.Encode(d)
} }

View File

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

View File

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

View File

@ -7,44 +7,44 @@ import "fmt"
func main() { func main() {
// To create an empty map, use the builtin `make`: // To create an empty map, use the builtin `make`:
// `make(map[key-type]val-type)`. // `make(map[key-type]val-type)`.
m := make(map[string]int) m := make(map[string]int)
// Set key/value pairs using typical `name[key] = val` // Set key/value pairs using typical `name[key] = val`
// syntax. // syntax.
m["k1"] = 7 m["k1"] = 7
m["k2"] = 13 m["k2"] = 13
// Printing a map with e.g. `fmt.Println` will show all of // Printing a map with e.g. `fmt.Println` will show all of
// its key/value pairs. // its key/value pairs.
fmt.Println("map:", m) fmt.Println("map:", m)
// Get a value for a key with `name[key]`. // Get a value for a key with `name[key]`.
v1 := m["k1"] v1 := m["k1"]
fmt.Println("v1: ", v1) fmt.Println("v1: ", v1)
// The builtin `len` returns the number of key/value // The builtin `len` returns the number of key/value
// pairs when called on a map. // pairs when called on a map.
fmt.Println("len:", len(m)) fmt.Println("len:", len(m))
// The builtin `delete` removes key/value pairs from // The builtin `delete` removes key/value pairs from
// a map. // a map.
delete(m, "k2") delete(m, "k2")
fmt.Println("map:", m) fmt.Println("map:", m)
// The optional second return value when getting a // The optional second return value when getting a
// value from a map indicates if the key was present // value from a map indicates if the key was present
// in the map. This can be used to disambiguate // in the map. This can be used to disambiguate
// between missing keys and keys with zero values // between missing keys and keys with zero values
// like `0` or `""`. Here we didn't need the value // like `0` or `""`. Here we didn't need the value
// itself, so we ignored it with the _blank identifier_ // itself, so we ignored it with the _blank identifier_
// `_`. // `_`.
_, prs := m["k2"] _, prs := m["k2"]
fmt.Println("prs:", prs) fmt.Println("prs:", prs)
// You can also declare and initialize a new map in // You can also declare and initialize a new map in
// the same line with this syntax. // the same line with this syntax.
n := map[string]int{"foo": 1, "bar": 2} n := map[string]int{"foo": 1, "bar": 2}
fmt.Println("map:", n) fmt.Println("map:", n)
} }

View File

@ -5,33 +5,33 @@ package main
import "fmt" import "fmt"
type rect struct { type rect struct {
width, height int width, height int
} }
// This `area` method has a _receiver type_ of `*rect`. // This `area` method has a _receiver type_ of `*rect`.
func (r *rect) area() int { func (r *rect) area() int {
return r.width * r.height return r.width * r.height
} }
// Methods can be defined for either pointer or value // Methods can be defined for either pointer or value
// receiver types. Here's an example of a value receiver. // receiver types. Here's an example of a value receiver.
func (r rect) perim() int { func (r rect) perim() int {
return 2*r.width + 2*r.height return 2*r.width + 2*r.height
} }
func main() { func main() {
r := rect{width: 10, height: 5} r := rect{width: 10, height: 5}
// Here we call the 2 methods defined for our struct. // Here we call the 2 methods defined for our struct.
fmt.Println("area: ", r.area()) fmt.Println("area: ", r.area())
fmt.Println("perim:", r.perim()) fmt.Println("perim:", r.perim())
// Go automatically handles conversion between values // Go automatically handles conversion between values
// and pointers for method calls. You may want to use // and pointers for method calls. You may want to use
// a pointer receiver type to avoid copying on method // a pointer receiver type to avoid copying on method
// calls or to allow the method to mutate the // calls or to allow the method to mutate the
// receiving struct. // receiving struct.
rp := &r rp := &r
fmt.Println("area: ", rp.area()) fmt.Println("area: ", rp.area())
fmt.Println("perim:", rp.perim()) fmt.Println("perim:", rp.perim())
} }

View File

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

View File

@ -9,19 +9,19 @@ import "fmt"
// The `(int, int)` in this function signature shows that // The `(int, int)` in this function signature shows that
// the function returns 2 `int`s. // the function returns 2 `int`s.
func vals() (int, int) { func vals() (int, int) {
return 3, 7 return 3, 7
} }
func main() { func main() {
// Here we use the 2 different return values from the // Here we use the 2 different return values from the
// call with _multiple assignment_. // call with _multiple assignment_.
a, b := vals() a, b := vals()
fmt.Println(a) fmt.Println(a)
fmt.Println(b) fmt.Println(b)
// If you only want a subset of the returned values, // If you only want a subset of the returned values,
// use the blank identifier `_`. // use the blank identifier `_`.
_, c := vals() _, c := vals()
fmt.Println(c) fmt.Println(c)
} }

View File

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

View File

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

View File

@ -8,42 +8,42 @@ package main
import "fmt" import "fmt"
func main() { func main() {
messages := make(chan string) messages := make(chan string)
signals := make(chan bool) signals := make(chan bool)
// Here's a non-blocking receive. If a value is // Here's a non-blocking receive. If a value is
// available on `messages` then `select` will take // available on `messages` then `select` will take
// the `<-messages` `case` with that value. If not // the `<-messages` `case` with that value. If not
// it will immediately take the `default` case. // it will immediately take the `default` case.
select { select {
case msg := <-messages: case msg := <-messages:
fmt.Println("received message", msg) fmt.Println("received message", msg)
default: default:
fmt.Println("no message received") fmt.Println("no message received")
} }
// A non-blocking send works similarly. Here `msg` // A non-blocking send works similarly. Here `msg`
// cannot be sent to the `messages` channel, because // cannot be sent to the `messages` channel, because
// the channel has no buffer and there is no receiver. // the channel has no buffer and there is no receiver.
// Therefore the `default` case is selected. // Therefore the `default` case is selected.
msg := "hi" msg := "hi"
select { select {
case messages <- msg: case messages <- msg:
fmt.Println("sent message", msg) fmt.Println("sent message", msg)
default: default:
fmt.Println("no message sent") fmt.Println("no message sent")
} }
// We can use multiple `case`s above the `default` // We can use multiple `case`s above the `default`
// clause to implement a multi-way non-blocking // clause to implement a multi-way non-blocking
// select. Here we attempt non-blocking receives // select. Here we attempt non-blocking receives
// on both `messages` and `signals`. // on both `messages` and `signals`.
select { select {
case msg := <-messages: case msg := <-messages:
fmt.Println("received message", msg) fmt.Println("received message", msg)
case sig := <-signals: case sig := <-signals:
fmt.Println("received signal", sig) fmt.Println("received signal", sig)
default: default:
fmt.Println("no activity") fmt.Println("no activity")
} }
} }

View File

@ -10,31 +10,31 @@ import "fmt"
func main() { func main() {
// With `ParseFloat`, this `64` tells how many bits of // With `ParseFloat`, this `64` tells how many bits of
// precision to parse. // precision to parse.
f, _ := strconv.ParseFloat("1.234", 64) f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) fmt.Println(f)
// For `ParseInt`, the `0` means infer the base from // For `ParseInt`, the `0` means infer the base from
// the string. `64` requires that the result fit in 64 // the string. `64` requires that the result fit in 64
// bits. // bits.
i, _ := strconv.ParseInt("123", 0, 64) i, _ := strconv.ParseInt("123", 0, 64)
fmt.Println(i) fmt.Println(i)
// `ParseInt` will recognize hex-formatted numbers. // `ParseInt` will recognize hex-formatted numbers.
d, _ := strconv.ParseInt("0x1c8", 0, 64) d, _ := strconv.ParseInt("0x1c8", 0, 64)
fmt.Println(d) fmt.Println(d)
// A `ParseUint` is also available. // A `ParseUint` is also available.
u, _ := strconv.ParseUint("789", 0, 64) u, _ := strconv.ParseUint("789", 0, 64)
fmt.Println(u) fmt.Println(u)
// `Atoi` is a convenience function for basic base-10 // `Atoi` is a convenience function for basic base-10
// `int` parsing. // `int` parsing.
k, _ := strconv.Atoi("135") k, _ := strconv.Atoi("135")
fmt.Println(k) fmt.Println(k)
// Parse functions return an error on bad input. // Parse functions return an error on bad input.
_, e := strconv.Atoi("wat") _, e := strconv.Atoi("wat")
fmt.Println(e) fmt.Println(e)
} }

View File

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

View File

@ -9,17 +9,17 @@ import "os"
func main() { func main() {
// We'll use panic throughout this site to check for // We'll use panic throughout this site to check for
// unexpected errors. This is the only program on the // unexpected errors. This is the only program on the
// site designed to panic. // site designed to panic.
panic("a problem") panic("a problem")
// A common use of panic is to abort if a function // A common use of panic is to abort if a function
// returns an error value that we don't know how to // returns an error value that we don't know how to
// (or want to) handle. Here's an example of // (or want to) handle. Here's an example of
// `panic`king if we get an unexpected error when creating a new file. // `panic`king if we get an unexpected error when creating a new file.
_, err := os.Create("/tmp/file") _, err := os.Create("/tmp/file")
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }

View File

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

View File

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

View File

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

View File

@ -10,45 +10,45 @@ import "math/rand"
func main() { func main() {
// For example, `rand.Intn` returns a random `int` n, // For example, `rand.Intn` returns a random `int` n,
// `0 <= n < 100`. // `0 <= n < 100`.
fmt.Print(rand.Intn(100), ",") fmt.Print(rand.Intn(100), ",")
fmt.Print(rand.Intn(100)) fmt.Print(rand.Intn(100))
fmt.Println() fmt.Println()
// `rand.Float64` returns a `float64` `f`, // `rand.Float64` returns a `float64` `f`,
// `0.0 <= f < 1.0`. // `0.0 <= f < 1.0`.
fmt.Println(rand.Float64()) fmt.Println(rand.Float64())
// This can be used to generate random floats in // This can be used to generate random floats in
// other ranges, for example `5.0 <= f' < 10.0`. // other ranges, for example `5.0 <= f' < 10.0`.
fmt.Print((rand.Float64()*5)+5, ",") fmt.Print((rand.Float64()*5)+5, ",")
fmt.Print((rand.Float64() * 5) + 5) fmt.Print((rand.Float64() * 5) + 5)
fmt.Println() fmt.Println()
// The default number generator is deterministic, so it'll // The default number generator is deterministic, so it'll
// produce the same sequence of numbers each time by default. // produce the same sequence of numbers each time by default.
// To produce varying sequences, give it a seed that changes. // To produce varying sequences, give it a seed that changes.
// Note that this is not safe to use for random numbers you // Note that this is not safe to use for random numbers you
// intend to be secret, use `crypto/rand` for those. // intend to be secret, use `crypto/rand` for those.
s1 := rand.NewSource(time.Now().UnixNano()) s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1) r1 := rand.New(s1)
// Call the resulting `rand.Rand` just like the // Call the resulting `rand.Rand` just like the
// functions on the `rand` package. // functions on the `rand` package.
fmt.Print(r1.Intn(100), ",") fmt.Print(r1.Intn(100), ",")
fmt.Print(r1.Intn(100)) fmt.Print(r1.Intn(100))
fmt.Println() fmt.Println()
// If you seed a source with the same number, it // If you seed a source with the same number, it
// produces the same sequence of random numbers. // produces the same sequence of random numbers.
s2 := rand.NewSource(42) s2 := rand.NewSource(42)
r2 := rand.New(s2) r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",") fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100)) fmt.Print(r2.Intn(100))
fmt.Println() fmt.Println()
s3 := rand.NewSource(42) s3 := rand.NewSource(42)
r3 := rand.New(s3) r3 := rand.New(s3)
fmt.Print(r3.Intn(100), ",") fmt.Print(r3.Intn(100), ",")
fmt.Print(r3.Intn(100)) fmt.Print(r3.Intn(100))
} }

View File

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

View File

@ -9,17 +9,17 @@ import "fmt"
func main() { func main() {
// We'll iterate over 2 values in the `queue` channel. // We'll iterate over 2 values in the `queue` channel.
queue := make(chan string, 2) queue := make(chan string, 2)
queue <- "one" queue <- "one"
queue <- "two" queue <- "two"
close(queue) close(queue)
// This `range` iterates over each element as it's // This `range` iterates over each element as it's
// received from `queue`. Because we `close`d the // received from `queue`. Because we `close`d the
// channel above, the iteration terminates after // channel above, the iteration terminates after
// receiving the 2 elements. // receiving the 2 elements.
for elem := range queue { for elem := range queue {
fmt.Println(elem) fmt.Println(elem)
} }
} }

View File

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

View File

@ -8,41 +8,41 @@ import "fmt"
func main() { func main() {
// Here we use `range` to sum the numbers in a slice. // Here we use `range` to sum the numbers in a slice.
// Arrays work like this too. // Arrays work like this too.
nums := []int{2, 3, 4} nums := []int{2, 3, 4}
sum := 0 sum := 0
for _, num := range nums { for _, num := range nums {
sum += num sum += num
} }
fmt.Println("sum:", sum) fmt.Println("sum:", sum)
// `range` on arrays and slices provides both the // `range` on arrays and slices provides both the
// index and value for each entry. Above we didn't // index and value for each entry. Above we didn't
// need the index, so we ignored it with the // need the index, so we ignored it with the
// blank identifier `_`. Sometimes we actually want // blank identifier `_`. Sometimes we actually want
// the indexes though. // the indexes though.
for i, num := range nums { for i, num := range nums {
if num == 3 { if num == 3 {
fmt.Println("index:", i) fmt.Println("index:", i)
} }
} }
// `range` on map iterates over key/value pairs. // `range` on map iterates over key/value pairs.
kvs := map[string]string{"a": "apple", "b": "banana"} kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs { for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v) fmt.Printf("%s -> %s\n", k, v)
} }
// `range` can also iterate over just the keys of a map. // `range` can also iterate over just the keys of a map.
for k := range kvs { for k := range kvs {
fmt.Println("key:", k) fmt.Println("key:", k)
} }
// `range` on strings iterates over Unicode code // `range` on strings iterates over Unicode code
// points. The first value is the starting byte index // points. The first value is the starting byte index
// of the `rune` and the second the `rune` itself. // of the `rune` and the second the `rune` itself.
for i, c := range "go" { for i, c := range "go" {
fmt.Println(i, c) fmt.Println(i, c)
} }
} }

View File

@ -1,2 +1,2 @@
ebe328a57f3d34708709ca99d3304af1733592d9 ebe328a57f3d34708709ca99d3304af1733592d9
SkL_AS-1Jd JTY1VAUjfBw

View File

@ -11,59 +11,59 @@ import "fmt"
func main() { func main() {
// First we'll look at basic rate limiting. Suppose // First we'll look at basic rate limiting. Suppose
// we want to limit our handling of incoming requests. // we want to limit our handling of incoming requests.
// We'll serve these requests off a channel of the // We'll serve these requests off a channel of the
// same name. // same name.
requests := make(chan int, 5) requests := make(chan int, 5)
for i := 1; i <= 5; i++ { for i := 1; i <= 5; i++ {
requests <- i requests <- i
} }
close(requests) close(requests)
// This `limiter` channel will receive a value // This `limiter` channel will receive a value
// every 200 milliseconds. This is the regulator in // every 200 milliseconds. This is the regulator in
// our rate limiting scheme. // our rate limiting scheme.
limiter := time.Tick(200 * time.Millisecond) limiter := time.Tick(200 * time.Millisecond)
// By blocking on a receive from the `limiter` channel // By blocking on a receive from the `limiter` channel
// before serving each request, we limit ourselves to // before serving each request, we limit ourselves to
// 1 request every 200 milliseconds. // 1 request every 200 milliseconds.
for req := range requests { for req := range requests {
<-limiter <-limiter
fmt.Println("request", req, time.Now()) fmt.Println("request", req, time.Now())
} }
// We may want to allow short bursts of requests in // We may want to allow short bursts of requests in
// our rate limiting scheme while preserving the // our rate limiting scheme while preserving the
// overall rate limit. We can accomplish this by // overall rate limit. We can accomplish this by
// buffering our limiter channel. This `burstyLimiter` // buffering our limiter channel. This `burstyLimiter`
// channel will allow bursts of up to 3 events. // channel will allow bursts of up to 3 events.
burstyLimiter := make(chan time.Time, 3) burstyLimiter := make(chan time.Time, 3)
// Fill up the channel to represent allowed bursting. // Fill up the channel to represent allowed bursting.
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
burstyLimiter <- time.Now() burstyLimiter <- time.Now()
} }
// Every 200 milliseconds we'll try to add a new // Every 200 milliseconds we'll try to add a new
// value to `burstyLimiter`, up to its limit of 3. // value to `burstyLimiter`, up to its limit of 3.
go func() { go func() {
for t := range time.Tick(200 * time.Millisecond) { for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t burstyLimiter <- t
} }
}() }()
// Now simulate 5 more incoming requests. The first // Now simulate 5 more incoming requests. The first
// 3 of these will benefit from the burst capability // 3 of these will benefit from the burst capability
// of `burstyLimiter`. // of `burstyLimiter`.
burstyRequests := make(chan int, 5) burstyRequests := make(chan int, 5)
for i := 1; i <= 5; i++ { for i := 1; i <= 5; i++ {
burstyRequests <- i burstyRequests <- i
} }
close(burstyRequests) close(burstyRequests)
for req := range burstyRequests { for req := range burstyRequests {
<-burstyLimiter <-burstyLimiter
fmt.Println("request", req, time.Now()) fmt.Println("request", req, time.Now())
} }
} }

View File

@ -5,80 +5,80 @@
package main package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
) )
// Reading files requires checking most calls for errors. // Reading files requires checking most calls for errors.
// This helper will streamline our error checks below. // This helper will streamline our error checks below.
func check(e error) { func check(e error) {
if e != nil { if e != nil {
panic(e) panic(e)
} }
} }
func main() { func main() {
// Perhaps the most basic file reading task is // Perhaps the most basic file reading task is
// slurping a file's entire contents into memory. // slurping a file's entire contents into memory.
dat, err := ioutil.ReadFile("/tmp/dat") dat, err := ioutil.ReadFile("/tmp/dat")
check(err) check(err)
fmt.Print(string(dat)) fmt.Print(string(dat))
// You'll often want more control over how and what // You'll often want more control over how and what
// parts of a file are read. For these tasks, start // parts of a file are read. For these tasks, start
// by `Open`ing a file to obtain an `os.File` value. // by `Open`ing a file to obtain an `os.File` value.
f, err := os.Open("/tmp/dat") f, err := os.Open("/tmp/dat")
check(err) check(err)
// Read some bytes from the beginning of the file. // Read some bytes from the beginning of the file.
// Allow up to 5 to be read but also note how many // Allow up to 5 to be read but also note how many
// actually were read. // actually were read.
b1 := make([]byte, 5) b1 := make([]byte, 5)
n1, err := f.Read(b1) n1, err := f.Read(b1)
check(err) check(err)
fmt.Printf("%d bytes: %s\n", n1, string(b1)) fmt.Printf("%d bytes: %s\n", n1, string(b1))
// You can also `Seek` to a known location in the file // You can also `Seek` to a known location in the file
// and `Read` from there. // and `Read` from there.
o2, err := f.Seek(6, 0) o2, err := f.Seek(6, 0)
check(err) check(err)
b2 := make([]byte, 2) b2 := make([]byte, 2)
n2, err := f.Read(b2) n2, err := f.Read(b2)
check(err) check(err)
fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2)) fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2))
// The `io` package provides some functions that may // The `io` package provides some functions that may
// be helpful for file reading. For example, reads // be helpful for file reading. For example, reads
// like the ones above can be more robustly // like the ones above can be more robustly
// implemented with `ReadAtLeast`. // implemented with `ReadAtLeast`.
o3, err := f.Seek(6, 0) o3, err := f.Seek(6, 0)
check(err) check(err)
b3 := make([]byte, 2) b3 := make([]byte, 2)
n3, err := io.ReadAtLeast(f, b3, 2) n3, err := io.ReadAtLeast(f, b3, 2)
check(err) check(err)
fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
// There is no built-in rewind, but `Seek(0, 0)` // There is no built-in rewind, but `Seek(0, 0)`
// accomplishes this. // accomplishes this.
_, err = f.Seek(0, 0) _, err = f.Seek(0, 0)
check(err) check(err)
// The `bufio` package implements a buffered // The `bufio` package implements a buffered
// reader that may be useful both for its efficiency // reader that may be useful both for its efficiency
// with many small reads and because of the additional // with many small reads and because of the additional
// reading methods it provides. // reading methods it provides.
r4 := bufio.NewReader(f) r4 := bufio.NewReader(f)
b4, err := r4.Peek(5) b4, err := r4.Peek(5)
check(err) check(err)
fmt.Printf("5 bytes: %s\n", string(b4)) fmt.Printf("5 bytes: %s\n", string(b4))
// Close the file when you're done (usually this would // Close the file when you're done (usually this would
// be scheduled immediately after `Open`ing with // be scheduled immediately after `Open`ing with
// `defer`). // `defer`).
f.Close() f.Close()
} }

View File

@ -1,2 +1,2 @@
2aa7a2e248065cebfa6f8eece3234b5ffa710273 2aa7a2e248065cebfa6f8eece3234b5ffa710273
2kEKXq-kUV GQgp-I3dLb2

View File

@ -9,12 +9,12 @@ import "fmt"
// This `fact` function calls itself until it reaches the // This `fact` function calls itself until it reaches the
// base case of `fact(0)`. // base case of `fact(0)`.
func fact(n int) int { func fact(n int) int {
if n == 0 { if n == 0 {
return 1 return 1
} }
return n * fact(n-1) return n * fact(n-1)
} }
func main() { func main() {
fmt.Println(fact(7)) fmt.Println(fact(7))
} }

View File

@ -1,2 +1,2 @@
5d1ba6b03a50ccae2a0f46865eb72c587e11857c 5d1ba6b03a50ccae2a0f46865eb72c587e11857c
RFn-rf42ap 4yUp5wLVyiG

View File

@ -10,72 +10,72 @@ import "regexp"
func main() { func main() {
// This tests whether a pattern matches a string. // This tests whether a pattern matches a string.
match, _ := regexp.MatchString("p([a-z]+)ch", "peach") match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
fmt.Println(match) fmt.Println(match)
// Above we used a string pattern directly, but for // Above we used a string pattern directly, but for
// other regexp tasks you'll need to `Compile` an // other regexp tasks you'll need to `Compile` an
// optimized `Regexp` struct. // optimized `Regexp` struct.
r, _ := regexp.Compile("p([a-z]+)ch") r, _ := regexp.Compile("p([a-z]+)ch")
// Many methods are available on these structs. Here's // Many methods are available on these structs. Here's
// a match test like we saw earlier. // a match test like we saw earlier.
fmt.Println(r.MatchString("peach")) fmt.Println(r.MatchString("peach"))
// This finds the match for the regexp. // This finds the match for the regexp.
fmt.Println(r.FindString("peach punch")) fmt.Println(r.FindString("peach punch"))
// This also finds the first match but returns the // This also finds the first match but returns the
// start and end indexes for the match instead of the // start and end indexes for the match instead of the
// matching text. // matching text.
fmt.Println(r.FindStringIndex("peach punch")) fmt.Println(r.FindStringIndex("peach punch"))
// The `Submatch` variants include information about // The `Submatch` variants include information about
// both the whole-pattern matches and the submatches // both the whole-pattern matches and the submatches
// within those matches. For example this will return // within those matches. For example this will return
// information for both `p([a-z]+)ch` and `([a-z]+)`. // information for both `p([a-z]+)ch` and `([a-z]+)`.
fmt.Println(r.FindStringSubmatch("peach punch")) fmt.Println(r.FindStringSubmatch("peach punch"))
// Similarly this will return information about the // Similarly this will return information about the
// indexes of matches and submatches. // indexes of matches and submatches.
fmt.Println(r.FindStringSubmatchIndex("peach punch")) fmt.Println(r.FindStringSubmatchIndex("peach punch"))
// The `All` variants of these functions apply to all // The `All` variants of these functions apply to all
// matches in the input, not just the first. For // matches in the input, not just the first. For
// example to find all matches for a regexp. // example to find all matches for a regexp.
fmt.Println(r.FindAllString("peach punch pinch", -1)) fmt.Println(r.FindAllString("peach punch pinch", -1))
// These `All` variants are available for the other // These `All` variants are available for the other
// functions we saw above as well. // functions we saw above as well.
fmt.Println(r.FindAllStringSubmatchIndex( fmt.Println(r.FindAllStringSubmatchIndex(
"peach punch pinch", -1)) "peach punch pinch", -1))
// Providing a non-negative integer as the second // Providing a non-negative integer as the second
// argument to these functions will limit the number // argument to these functions will limit the number
// of matches. // of matches.
fmt.Println(r.FindAllString("peach punch pinch", 2)) fmt.Println(r.FindAllString("peach punch pinch", 2))
// Our examples above had string arguments and used // Our examples above had string arguments and used
// names like `MatchString`. We can also provide // names like `MatchString`. We can also provide
// `[]byte` arguments and drop `String` from the // `[]byte` arguments and drop `String` from the
// function name. // function name.
fmt.Println(r.Match([]byte("peach"))) fmt.Println(r.Match([]byte("peach")))
// When creating constants with regular expressions // When creating constants with regular expressions
// you can use the `MustCompile` variation of // you can use the `MustCompile` variation of
// `Compile`. A plain `Compile` won't work for // `Compile`. A plain `Compile` won't work for
// constants because it has 2 return values. // constants because it has 2 return values.
r = regexp.MustCompile("p([a-z]+)ch") r = regexp.MustCompile("p([a-z]+)ch")
fmt.Println(r) fmt.Println(r)
// The `regexp` package can also be used to replace // The `regexp` package can also be used to replace
// subsets of strings with other values. // subsets of strings with other values.
fmt.Println(r.ReplaceAllString("a peach", "<fruit>")) fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
// The `Func` variant allows you to transform matched // The `Func` variant allows you to transform matched
// text with a given function. // text with a given function.
in := []byte("a peach") in := []byte("a peach")
out := r.ReplaceAllFunc(in, bytes.ToUpper) out := r.ReplaceAllFunc(in, bytes.ToUpper)
fmt.Println(string(out)) fmt.Println(string(out))
} }

View File

@ -1,2 +1,2 @@
7cde6b9af5cf6c47606001dd54eee468a6c61dbb 7cde6b9af5cf6c47606001dd54eee468a6c61dbb
YeSiBTfhFq qR5gn2l0AGa

View File

@ -9,30 +9,30 @@ import "fmt"
func main() { func main() {
// For our example we'll select across two channels. // For our example we'll select across two channels.
c1 := make(chan string) c1 := make(chan string)
c2 := make(chan string) c2 := make(chan string)
// Each channel will receive a value after some amount // Each channel will receive a value after some amount
// of time, to simulate e.g. blocking RPC operations // of time, to simulate e.g. blocking RPC operations
// executing in concurrent goroutines. // executing in concurrent goroutines.
go func() { go func() {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
c1 <- "one" c1 <- "one"
}() }()
go func() { go func() {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
c2 <- "two" c2 <- "two"
}() }()
// We'll use `select` to await both of these values // We'll use `select` to await both of these values
// simultaneously, printing each one as it arrives. // simultaneously, printing each one as it arrives.
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
select { select {
case msg1 := <-c1: case msg1 := <-c1:
fmt.Println("received", msg1) fmt.Println("received", msg1)
case msg2 := <-c2: case msg2 := <-c2:
fmt.Println("received", msg2) fmt.Println("received", msg2)
} }
} }
} }

View File

@ -13,25 +13,25 @@ import "crypto/sha1"
import "fmt" import "fmt"
func main() { func main() {
s := "sha1 this string" s := "sha1 this string"
// The pattern for generating a hash is `sha1.New()`, // The pattern for generating a hash is `sha1.New()`,
// `sha1.Write(bytes)`, then `sha1.Sum([]byte{})`. // `sha1.Write(bytes)`, then `sha1.Sum([]byte{})`.
// Here we start with a new hash. // Here we start with a new hash.
h := sha1.New() h := sha1.New()
// `Write` expects bytes. If you have a string `s`, // `Write` expects bytes. If you have a string `s`,
// use `[]byte(s)` to coerce it to bytes. // use `[]byte(s)` to coerce it to bytes.
h.Write([]byte(s)) h.Write([]byte(s))
// This gets the finalized hash result as a byte // This gets the finalized hash result as a byte
// slice. The argument to `Sum` can be used to append // slice. The argument to `Sum` can be used to append
// to an existing byte slice: it usually isn't needed. // to an existing byte slice: it usually isn't needed.
bs := h.Sum(nil) bs := h.Sum(nil)
// SHA1 values are often printed in hex, for example // SHA1 values are often printed in hex, for example
// in git commits. Use the `%x` format verb to convert // in git commits. Use the `%x` format verb to convert
// a hash results to a hex string. // a hash results to a hex string.
fmt.Println(s) fmt.Println(s)
fmt.Printf("%x\n", bs) fmt.Printf("%x\n", bs)
} }

View File

@ -1,2 +1,2 @@
6a896270e34f2696b881a8fa7e68bfff57dee51f 6a896270e34f2696b881a8fa7e68bfff57dee51f
YUaWWEeB4U 1oT-5GBUkLr

View File

@ -14,31 +14,31 @@ import "syscall"
func main() { func main() {
// Go signal notification works by sending `os.Signal` // Go signal notification works by sending `os.Signal`
// values on a channel. We'll create a channel to // values on a channel. We'll create a channel to
// receive these notifications (we'll also make one to // receive these notifications (we'll also make one to
// notify us when the program can exit). // notify us when the program can exit).
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
done := make(chan bool, 1) done := make(chan bool, 1)
// `signal.Notify` registers the given channel to // `signal.Notify` registers the given channel to
// receive notifications of the specified signals. // receive notifications of the specified signals.
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
// This goroutine executes a blocking receive for // This goroutine executes a blocking receive for
// signals. When it gets one it'll print it out // signals. When it gets one it'll print it out
// and then notify the program that it can finish. // and then notify the program that it can finish.
go func() { go func() {
sig := <-sigs sig := <-sigs
fmt.Println() fmt.Println()
fmt.Println(sig) fmt.Println(sig)
done <- true done <- true
}() }()
// The program will wait here until it gets the // The program will wait here until it gets the
// expected signal (as indicated by the goroutine // expected signal (as indicated by the goroutine
// above sending a value on `done`) and then exit. // above sending a value on `done`) and then exit.
fmt.Println("awaiting signal") fmt.Println("awaiting signal")
<-done <-done
fmt.Println("exiting") fmt.Println("exiting")
} }

View File

@ -1,2 +1,2 @@
9720d747e3ab2893df508a70cbb341c90fdd7ca1 9720d747e3ab2893df508a70cbb341c90fdd7ca1
BlkqAtKsxo 9koJAW1raI5

View File

@ -7,70 +7,70 @@ import "fmt"
func main() { func main() {
// Unlike arrays, slices are typed only by the // Unlike arrays, slices are typed only by the
// elements they contain (not the number of elements). // elements they contain (not the number of elements).
// To create an empty slice with non-zero length, use // To create an empty slice with non-zero length, use
// the builtin `make`. Here we make a slice of // the builtin `make`. Here we make a slice of
// `string`s of length `3` (initially zero-valued). // `string`s of length `3` (initially zero-valued).
s := make([]string, 3) s := make([]string, 3)
fmt.Println("emp:", s) fmt.Println("emp:", s)
// We can set and get just like with arrays. // We can set and get just like with arrays.
s[0] = "a" s[0] = "a"
s[1] = "b" s[1] = "b"
s[2] = "c" s[2] = "c"
fmt.Println("set:", s) fmt.Println("set:", s)
fmt.Println("get:", s[2]) fmt.Println("get:", s[2])
// `len` returns the length of the slice as expected. // `len` returns the length of the slice as expected.
fmt.Println("len:", len(s)) fmt.Println("len:", len(s))
// In addition to these basic operations, slices // In addition to these basic operations, slices
// support several more that make them richer than // support several more that make them richer than
// arrays. One is the builtin `append`, which // arrays. One is the builtin `append`, which
// returns a slice containing one or more new values. // returns a slice containing one or more new values.
// Note that we need to accept a return value from // Note that we need to accept a return value from
// `append` as we may get a new slice value. // `append` as we may get a new slice value.
s = append(s, "d") s = append(s, "d")
s = append(s, "e", "f") s = append(s, "e", "f")
fmt.Println("apd:", s) fmt.Println("apd:", s)
// Slices can also be `copy`'d. Here we create an // Slices can also be `copy`'d. Here we create an
// empty slice `c` of the same length as `s` and copy // empty slice `c` of the same length as `s` and copy
// into `c` from `s`. // into `c` from `s`.
c := make([]string, len(s)) c := make([]string, len(s))
copy(c, s) copy(c, s)
fmt.Println("cpy:", c) fmt.Println("cpy:", c)
// Slices support a "slice" operator with the syntax // Slices support a "slice" operator with the syntax
// `slice[low:high]`. For example, this gets a slice // `slice[low:high]`. For example, this gets a slice
// of the elements `s[2]`, `s[3]`, and `s[4]`. // of the elements `s[2]`, `s[3]`, and `s[4]`.
l := s[2:5] l := s[2:5]
fmt.Println("sl1:", l) fmt.Println("sl1:", l)
// This slices up to (but excluding) `s[5]`. // This slices up to (but excluding) `s[5]`.
l = s[:5] l = s[:5]
fmt.Println("sl2:", l) fmt.Println("sl2:", l)
// And this slices up from (and including) `s[2]`. // And this slices up from (and including) `s[2]`.
l = s[2:] l = s[2:]
fmt.Println("sl3:", l) fmt.Println("sl3:", l)
// We can declare and initialize a variable for slice // We can declare and initialize a variable for slice
// in a single line as well. // in a single line as well.
t := []string{"g", "h", "i"} t := []string{"g", "h", "i"}
fmt.Println("dcl:", t) fmt.Println("dcl:", t)
// Slices can be composed into multi-dimensional data // Slices can be composed into multi-dimensional data
// structures. The length of the inner slices can // structures. The length of the inner slices can
// vary, unlike with multi-dimensional arrays. // vary, unlike with multi-dimensional arrays.
twoD := make([][]int, 3) twoD := make([][]int, 3)
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
innerLen := i + 1 innerLen := i + 1
twoD[i] = make([]int, innerLen) twoD[i] = make([]int, innerLen)
for j := 0; j < innerLen; j++ { for j := 0; j < innerLen; j++ {
twoD[i][j] = i + j twoD[i][j] = i + j
} }
} }
fmt.Println("2d: ", twoD) fmt.Println("2d: ", twoD)
} }

View File

@ -23,13 +23,13 @@ type byLength []string
// want to sort in order of increasing string length, so // want to sort in order of increasing string length, so
// we use `len(s[i])` and `len(s[j])` here. // we use `len(s[i])` and `len(s[j])` here.
func (s byLength) Len() int { func (s byLength) Len() int {
return len(s) return len(s)
} }
func (s byLength) Swap(i, j int) { func (s byLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i] s[i], s[j] = s[j], s[i]
} }
func (s byLength) Less(i, j int) bool { func (s byLength) Less(i, j int) bool {
return len(s[i]) < len(s[j]) return len(s[i]) < len(s[j])
} }
// With all of this in place, we can now implement our // With all of this in place, we can now implement our
@ -37,7 +37,7 @@ func (s byLength) Less(i, j int) bool {
// to `byLength`, and then use `sort.Sort` on that typed // to `byLength`, and then use `sort.Sort` on that typed
// slice. // slice.
func main() { func main() {
fruits := []string{"peach", "banana", "kiwi"} fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(byLength(fruits)) sort.Sort(byLength(fruits))
fmt.Println(fruits) fmt.Println(fruits)
} }

View File

@ -9,21 +9,21 @@ import "sort"
func main() { func main() {
// Sort methods are specific to the builtin type; // Sort methods are specific to the builtin type;
// here's an example for strings. Note that sorting is // here's an example for strings. Note that sorting is
// in-place, so it changes the given slice and doesn't // in-place, so it changes the given slice and doesn't
// return a new one. // return a new one.
strs := []string{"c", "a", "b"} strs := []string{"c", "a", "b"}
sort.Strings(strs) sort.Strings(strs)
fmt.Println("Strings:", strs) fmt.Println("Strings:", strs)
// An example of sorting `int`s. // An example of sorting `int`s.
ints := []int{7, 2, 4} ints := []int{7, 2, 4}
sort.Ints(ints) sort.Ints(ints)
fmt.Println("Ints: ", ints) fmt.Println("Ints: ", ints)
// We can also use `sort` to check if a slice is // We can also use `sort` to check if a slice is
// already in sorted order. // already in sorted order.
s := sort.IntsAreSorted(ints) s := sort.IntsAreSorted(ints)
fmt.Println("Sorted: ", s) fmt.Println("Sorted: ", s)
} }

View File

@ -1,2 +1,2 @@
4e576421f2bdbd11847c367d223bd30d0e301990 4e576421f2bdbd11847c367d223bd30d0e301990
roQOJXtqAb e6hp3Rn-oH6

View File

@ -13,59 +13,59 @@ import "os/exec"
func main() { func main() {
// We'll start with a simple command that takes no // We'll start with a simple command that takes no
// arguments or input and just prints something to // arguments or input and just prints something to
// stdout. The `exec.Command` helper creates an object // stdout. The `exec.Command` helper creates an object
// to represent this external process. // to represent this external process.
dateCmd := exec.Command("date") dateCmd := exec.Command("date")
// `.Output` is another helper that handles the common // `.Output` is another helper that handles the common
// case of running a command, waiting for it to finish, // case of running a command, waiting for it to finish,
// and collecting its output. If there were no errors, // and collecting its output. If there were no errors,
// `dateOut` will hold bytes with the date info. // `dateOut` will hold bytes with the date info.
dateOut, err := dateCmd.Output() dateOut, err := dateCmd.Output()
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println("> date") fmt.Println("> date")
fmt.Println(string(dateOut)) fmt.Println(string(dateOut))
// Next we'll look at a slightly more involved case // Next we'll look at a slightly more involved case
// where we pipe data to the external process on its // where we pipe data to the external process on its
// `stdin` and collect the results from its `stdout`. // `stdin` and collect the results from its `stdout`.
grepCmd := exec.Command("grep", "hello") grepCmd := exec.Command("grep", "hello")
// Here we explicitly grab input/output pipes, start // Here we explicitly grab input/output pipes, start
// the process, write some input to it, read the // the process, write some input to it, read the
// resulting output, and finally wait for the process // resulting output, and finally wait for the process
// to exit. // to exit.
grepIn, _ := grepCmd.StdinPipe() grepIn, _ := grepCmd.StdinPipe()
grepOut, _ := grepCmd.StdoutPipe() grepOut, _ := grepCmd.StdoutPipe()
grepCmd.Start() grepCmd.Start()
grepIn.Write([]byte("hello grep\ngoodbye grep")) grepIn.Write([]byte("hello grep\ngoodbye grep"))
grepIn.Close() grepIn.Close()
grepBytes, _ := ioutil.ReadAll(grepOut) grepBytes, _ := ioutil.ReadAll(grepOut)
grepCmd.Wait() grepCmd.Wait()
// We ommited error checks in the above example, but // We ommited error checks in the above example, but
// you could use the usual `if err != nil` pattern for // you could use the usual `if err != nil` pattern for
// all of them. We also only collect the `StdoutPipe` // all of them. We also only collect the `StdoutPipe`
// results, but you could collect the `StderrPipe` in // results, but you could collect the `StderrPipe` in
// exactly the same way. // exactly the same way.
fmt.Println("> grep hello") fmt.Println("> grep hello")
fmt.Println(string(grepBytes)) fmt.Println(string(grepBytes))
// Note that when spawning commands we need to // Note that when spawning commands we need to
// provide an explicitly delineated command and // provide an explicitly delineated command and
// argument array, vs. being able to just pass in one // argument array, vs. being able to just pass in one
// command-line string. If you want to spawn a full // command-line string. If you want to spawn a full
// command with a string, you can use `bash`'s `-c` // command with a string, you can use `bash`'s `-c`
// option: // option:
lsCmd := exec.Command("bash", "-c", "ls -a -l -h") lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
lsOut, err := lsCmd.Output() lsOut, err := lsCmd.Output()
if err != nil { if err != nil {
panic(err) panic(err)
} }
fmt.Println("> ls -a -l -h") fmt.Println("> ls -a -l -h")
fmt.Println(string(lsOut)) fmt.Println(string(lsOut))
} }

View File

@ -1,2 +1,2 @@
0b676b93e41ac5434003c194bc038d5f3ce76bc8 0b676b93e41ac5434003c194bc038d5f3ce76bc8
y6SB6Mf2VQ 6HRWVK5gPYU

View File

@ -10,10 +10,10 @@
package main package main
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"sync/atomic" "sync/atomic"
"time" "time"
) )
// In this example our state will be owned by a single // In this example our state will be owned by a single
@ -25,91 +25,91 @@ import (
// encapsulate those requests and a way for the owning // encapsulate those requests and a way for the owning
// goroutine to respond. // goroutine to respond.
type readOp struct { type readOp struct {
key int key int
resp chan int resp chan int
} }
type writeOp struct { type writeOp struct {
key int key int
val int val int
resp chan bool resp chan bool
} }
func main() { func main() {
// As before we'll count how many operations we perform. // As before we'll count how many operations we perform.
var readOps uint64 var readOps uint64
var writeOps uint64 var writeOps uint64
// The `reads` and `writes` channels will be used by // The `reads` and `writes` channels will be used by
// other goroutines to issue read and write requests, // other goroutines to issue read and write requests,
// respectively. // respectively.
reads := make(chan *readOp) reads := make(chan *readOp)
writes := make(chan *writeOp) writes := make(chan *writeOp)
// Here is the goroutine that owns the `state`, which // Here is the goroutine that owns the `state`, which
// is a map as in the previous example but now private // is a map as in the previous example but now private
// to the stateful goroutine. This goroutine repeatedly // to the stateful goroutine. This goroutine repeatedly
// selects on the `reads` and `writes` channels, // selects on the `reads` and `writes` channels,
// responding to requests as they arrive. A response // responding to requests as they arrive. A response
// is executed by first performing the requested // is executed by first performing the requested
// operation and then sending a value on the response // operation and then sending a value on the response
// channel `resp` to indicate success (and the desired // channel `resp` to indicate success (and the desired
// value in the case of `reads`). // value in the case of `reads`).
go func() { go func() {
var state = make(map[int]int) var state = make(map[int]int)
for { for {
select { select {
case read := <-reads: case read := <-reads:
read.resp <- state[read.key] read.resp <- state[read.key]
case write := <-writes: case write := <-writes:
state[write.key] = write.val state[write.key] = write.val
write.resp <- true write.resp <- true
} }
} }
}() }()
// This starts 100 goroutines to issue reads to the // This starts 100 goroutines to issue reads to the
// state-owning goroutine via the `reads` channel. // state-owning goroutine via the `reads` channel.
// Each read requires constructing a `readOp`, sending // Each read requires constructing a `readOp`, sending
// it over the `reads` channel, and the receiving the // it over the `reads` channel, and the receiving the
// result over the provided `resp` channel. // result over the provided `resp` channel.
for r := 0; r < 100; r++ { for r := 0; r < 100; r++ {
go func() { go func() {
for { for {
read := &readOp{ read := &readOp{
key: rand.Intn(5), key: rand.Intn(5),
resp: make(chan int)} resp: make(chan int)}
reads <- read reads <- read
<-read.resp <-read.resp
atomic.AddUint64(&readOps, 1) atomic.AddUint64(&readOps, 1)
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
} }
}() }()
} }
// We start 10 writes as well, using a similar // We start 10 writes as well, using a similar
// approach. // approach.
for w := 0; w < 10; w++ { for w := 0; w < 10; w++ {
go func() { go func() {
for { for {
write := &writeOp{ write := &writeOp{
key: rand.Intn(5), key: rand.Intn(5),
val: rand.Intn(100), val: rand.Intn(100),
resp: make(chan bool)} resp: make(chan bool)}
writes <- write writes <- write
<-write.resp <-write.resp
atomic.AddUint64(&writeOps, 1) atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
} }
}() }()
} }
// Let the goroutines work for a second. // Let the goroutines work for a second.
time.Sleep(time.Second) time.Sleep(time.Second)
// Finally, capture and report the op counts. // Finally, capture and report the op counts.
readOpsFinal := atomic.LoadUint64(&readOps) readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal) fmt.Println("readOps:", readOpsFinal)
writeOpsFinal := atomic.LoadUint64(&writeOps) writeOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", writeOpsFinal) fmt.Println("writeOps:", writeOpsFinal)
} }

View File

@ -8,101 +8,101 @@ import "fmt"
import "os" import "os"
type point struct { type point struct {
x, y int x, y int
} }
func main() { func main() {
// Go offers several printing "verbs" designed to // Go offers several printing "verbs" designed to
// format general Go values. For example, this prints // format general Go values. For example, this prints
// an instance of our `point` struct. // an instance of our `point` struct.
p := point{1, 2} p := point{1, 2}
fmt.Printf("%v\n", p) fmt.Printf("%v\n", p)
// If the value is a struct, the `%+v` variant will // If the value is a struct, the `%+v` variant will
// include the struct's field names. // include the struct's field names.
fmt.Printf("%+v\n", p) fmt.Printf("%+v\n", p)
// The `%#v` variant prints a Go syntax representation // The `%#v` variant prints a Go syntax representation
// of the value, i.e. the source code snippet that // of the value, i.e. the source code snippet that
// would produce that value. // would produce that value.
fmt.Printf("%#v\n", p) fmt.Printf("%#v\n", p)
// To print the type of a value, use `%T`. // To print the type of a value, use `%T`.
fmt.Printf("%T\n", p) fmt.Printf("%T\n", p)
// Formatting booleans is straight-forward. // Formatting booleans is straight-forward.
fmt.Printf("%t\n", true) fmt.Printf("%t\n", true)
// There are many options for formatting integers. // There are many options for formatting integers.
// Use `%d` for standard, base-10 formatting. // Use `%d` for standard, base-10 formatting.
fmt.Printf("%d\n", 123) fmt.Printf("%d\n", 123)
// This prints a binary representation. // This prints a binary representation.
fmt.Printf("%b\n", 14) fmt.Printf("%b\n", 14)
// This prints the character corresponding to the // This prints the character corresponding to the
// given integer. // given integer.
fmt.Printf("%c\n", 33) fmt.Printf("%c\n", 33)
// `%x` provides hex encoding. // `%x` provides hex encoding.
fmt.Printf("%x\n", 456) fmt.Printf("%x\n", 456)
// There are also several formatting options for // There are also several formatting options for
// floats. For basic decimal formatting use `%f`. // floats. For basic decimal formatting use `%f`.
fmt.Printf("%f\n", 78.9) fmt.Printf("%f\n", 78.9)
// `%e` and `%E` format the float in (slightly // `%e` and `%E` format the float in (slightly
// different versions of) scientific notation. // different versions of) scientific notation.
fmt.Printf("%e\n", 123400000.0) fmt.Printf("%e\n", 123400000.0)
fmt.Printf("%E\n", 123400000.0) fmt.Printf("%E\n", 123400000.0)
// For basic string printing use `%s`. // For basic string printing use `%s`.
fmt.Printf("%s\n", "\"string\"") fmt.Printf("%s\n", "\"string\"")
// To double-quote strings as in Go source, use `%q`. // To double-quote strings as in Go source, use `%q`.
fmt.Printf("%q\n", "\"string\"") fmt.Printf("%q\n", "\"string\"")
// As with integers seen earlier, `%x` renders // As with integers seen earlier, `%x` renders
// the string in base-16, with two output characters // the string in base-16, with two output characters
// per byte of input. // per byte of input.
fmt.Printf("%x\n", "hex this") fmt.Printf("%x\n", "hex this")
// To print a representation of a pointer, use `%p`. // To print a representation of a pointer, use `%p`.
fmt.Printf("%p\n", &p) fmt.Printf("%p\n", &p)
// When formatting numbers you will often want to // When formatting numbers you will often want to
// control the width and precision of the resulting // control the width and precision of the resulting
// figure. To specify the width of an integer, use a // figure. To specify the width of an integer, use a
// number after the `%` in the verb. By default the // number after the `%` in the verb. By default the
// result will be right-justified and padded with // result will be right-justified and padded with
// spaces. // spaces.
fmt.Printf("|%6d|%6d|\n", 12, 345) fmt.Printf("|%6d|%6d|\n", 12, 345)
// You can also specify the width of printed floats, // You can also specify the width of printed floats,
// though usually you'll also want to restrict the // though usually you'll also want to restrict the
// decimal precision at the same time with the // decimal precision at the same time with the
// width.precision syntax. // width.precision syntax.
fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45) fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
// To left-justify, use the `-` flag. // To left-justify, use the `-` flag.
fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45) fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
// You may also want to control width when formatting // You may also want to control width when formatting
// strings, especially to ensure that they align in // strings, especially to ensure that they align in
// table-like output. For basic right-justified width. // table-like output. For basic right-justified width.
fmt.Printf("|%6s|%6s|\n", "foo", "b") fmt.Printf("|%6s|%6s|\n", "foo", "b")
// To left-justify use the `-` flag as with numbers. // To left-justify use the `-` flag as with numbers.
fmt.Printf("|%-6s|%-6s|\n", "foo", "b") fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
// So far we've seen `Printf`, which prints the // So far we've seen `Printf`, which prints the
// formatted string to `os.Stdout`. `Sprintf` formats // formatted string to `os.Stdout`. `Sprintf` formats
// and returns a string without printing it anywhere. // and returns a string without printing it anywhere.
s := fmt.Sprintf("a %s", "string") s := fmt.Sprintf("a %s", "string")
fmt.Println(s) fmt.Println(s)
// You can format+print to `io.Writers` other than // You can format+print to `io.Writers` other than
// `os.Stdout` using `Fprintf`. // `os.Stdout` using `Fprintf`.
fmt.Fprintf(os.Stderr, "an %s\n", "error") fmt.Fprintf(os.Stderr, "an %s\n", "error")
} }

View File

@ -1,2 +1,2 @@
5f39ae6d8f26d59a688a9a9d7d13a5c1d0f7a08b 5f39ae6d8f26d59a688a9a9d7d13a5c1d0f7a08b
JJAAFGxHVq CkBQ3CFpHQ9

View File

@ -13,32 +13,32 @@ var p = fmt.Println
func main() { func main() {
// Here's a sample of the functions available in // Here's a sample of the functions available in
// `strings`. Since these are functions from the // `strings`. Since these are functions from the
// package, not methods on the string object itself, // package, not methods on the string object itself,
// we need pass the string in question as the first // we need pass the string in question as the first
// argument to the function. You can find more // argument to the function. You can find more
// functions in the [`strings`](http://golang.org/pkg/strings/) // functions in the [`strings`](http://golang.org/pkg/strings/)
// package docs. // package docs.
p("Contains: ", s.Contains("test", "es")) p("Contains: ", s.Contains("test", "es"))
p("Count: ", s.Count("test", "t")) p("Count: ", s.Count("test", "t"))
p("HasPrefix: ", s.HasPrefix("test", "te")) p("HasPrefix: ", s.HasPrefix("test", "te"))
p("HasSuffix: ", s.HasSuffix("test", "st")) p("HasSuffix: ", s.HasSuffix("test", "st"))
p("Index: ", s.Index("test", "e")) p("Index: ", s.Index("test", "e"))
p("Join: ", s.Join([]string{"a", "b"}, "-")) p("Join: ", s.Join([]string{"a", "b"}, "-"))
p("Repeat: ", s.Repeat("a", 5)) p("Repeat: ", s.Repeat("a", 5))
p("Replace: ", s.Replace("foo", "o", "0", -1)) p("Replace: ", s.Replace("foo", "o", "0", -1))
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("Split: ", s.Split("a-b-c-d-e", "-"))
p("ToLower: ", s.ToLower("TEST")) p("ToLower: ", s.ToLower("TEST"))
p("ToUpper: ", s.ToUpper("test")) p("ToUpper: ", s.ToUpper("test"))
p() p()
// Not part of `strings`, but worth mentioning here, are // Not part of `strings`, but worth mentioning here, are
// the mechanisms for getting the length of a string in // the mechanisms for getting the length of a string in
// bytes and getting a byte by index. // bytes and getting a byte by index.
p("Len: ", len("hello")) p("Len: ", len("hello"))
p("Char:", "hello"[1]) p("Char:", "hello"[1])
} }
// Note that `len` and indexing above work at the byte level. // Note that `len` and indexing above work at the byte level.

View File

@ -1,2 +1,2 @@
17aa523bbd606fa0b624fae44b89812d46330755 17aa523bbd606fa0b624fae44b89812d46330755
Lf5_Zbg6or Vn4D3y4_711

View File

@ -8,34 +8,34 @@ import "fmt"
// This `person` struct type has `name` and `age` fields. // This `person` struct type has `name` and `age` fields.
type person struct { type person struct {
name string name string
age int age int
} }
func main() { func main() {
// This syntax creates a new struct. // This syntax creates a new struct.
fmt.Println(person{"Bob", 20}) fmt.Println(person{"Bob", 20})
// You can name the fields when initializing a struct. // You can name the fields when initializing a struct.
fmt.Println(person{name: "Alice", age: 30}) fmt.Println(person{name: "Alice", age: 30})
// Omitted fields will be zero-valued. // Omitted fields will be zero-valued.
fmt.Println(person{name: "Fred"}) fmt.Println(person{name: "Fred"})
// An `&` prefix yields a pointer to the struct. // An `&` prefix yields a pointer to the struct.
fmt.Println(&person{name: "Ann", age: 40}) fmt.Println(&person{name: "Ann", age: 40})
// Access struct fields with a dot. // Access struct fields with a dot.
s := person{name: "Sean", age: 50} s := person{name: "Sean", age: 50}
fmt.Println(s.name) fmt.Println(s.name)
// You can also use dots with struct pointers - the // You can also use dots with struct pointers - the
// pointers are automatically dereferenced. // pointers are automatically dereferenced.
sp := &s sp := &s
fmt.Println(sp.age) fmt.Println(sp.age)
// Structs are mutable. // Structs are mutable.
sp.age = 51 sp.age = 51
fmt.Println(sp.age) fmt.Println(sp.age)
} }

View File

@ -1,2 +1,2 @@
49cad39331ee5e9fb8d8dad99d3aff7f18a4e6d0 49cad39331ee5e9fb8d8dad99d3aff7f18a4e6d0
OMCP5KFC10 XMZpGsF4sWM

View File

@ -8,54 +8,54 @@ import "time"
func main() { func main() {
// Here's a basic `switch`. // Here's a basic `switch`.
i := 2 i := 2
fmt.Print("Write ", i, " as ") fmt.Print("Write ", i, " as ")
switch i { switch i {
case 1: case 1:
fmt.Println("one") fmt.Println("one")
case 2: case 2:
fmt.Println("two") fmt.Println("two")
case 3: case 3:
fmt.Println("three") fmt.Println("three")
} }
// You can use commas to separate multiple expressions // You can use commas to separate multiple expressions
// in the same `case` statement. We use the optional // in the same `case` statement. We use the optional
// `default` case in this example as well. // `default` case in this example as well.
switch time.Now().Weekday() { switch time.Now().Weekday() {
case time.Saturday, time.Sunday: case time.Saturday, time.Sunday:
fmt.Println("It's the weekend") fmt.Println("It's the weekend")
default: default:
fmt.Println("It's a weekday") fmt.Println("It's a weekday")
} }
// `switch` without an expression is an alternate way // `switch` without an expression is an alternate way
// to express if/else logic. Here we also show how the // to express if/else logic. Here we also show how the
// `case` expressions can be non-constants. // `case` expressions can be non-constants.
t := time.Now() t := time.Now()
switch { switch {
case t.Hour() < 12: case t.Hour() < 12:
fmt.Println("It's before noon") fmt.Println("It's before noon")
default: default:
fmt.Println("It's after noon") fmt.Println("It's after noon")
} }
// A type `switch` compares types instead of values. You // A type `switch` compares types instead of values. You
// can use this to discover the type of an interface // can use this to discover the type of an interface
// value. In this example, the variable `t` will have the // value. In this example, the variable `t` will have the
// type corresponding to its clause. // type corresponding to its clause.
whatAmI := func(i interface{}) { whatAmI := func(i interface{}) {
switch t := i.(type) { switch t := i.(type) {
case bool: case bool:
fmt.Println("I'm a bool") fmt.Println("I'm a bool")
case int: case int:
fmt.Println("I'm an int") fmt.Println("I'm an int")
default: default:
fmt.Printf("Don't know type %T\n", t) fmt.Printf("Don't know type %T\n", t)
} }
} }
whatAmI(true) whatAmI(true)
whatAmI(1) whatAmI(1)
whatAmI("hey") whatAmI("hey")
} }

View File

@ -11,21 +11,21 @@ import "fmt"
func main() { func main() {
// Tickers use a similar mechanism to timers: a // Tickers use a similar mechanism to timers: a
// channel that is sent values. Here we'll use the // channel that is sent values. Here we'll use the
// `range` builtin on the channel to iterate over // `range` builtin on the channel to iterate over
// the values as they arrive every 500ms. // the values as they arrive every 500ms.
ticker := time.NewTicker(500 * time.Millisecond) ticker := time.NewTicker(500 * time.Millisecond)
go func() { go func() {
for t := range ticker.C { for t := range ticker.C {
fmt.Println("Tick at", t) fmt.Println("Tick at", t)
} }
}() }()
// Tickers can be stopped like timers. Once a ticker // Tickers can be stopped like timers. Once a ticker
// is stopped it won't receive any more values on its // is stopped it won't receive any more values on its
// channel. We'll stop ours after 1600ms. // channel. We'll stop ours after 1600ms.
time.Sleep(1600 * time.Millisecond) time.Sleep(1600 * time.Millisecond)
ticker.Stop() ticker.Stop()
fmt.Println("Ticker stopped") fmt.Println("Ticker stopped")
} }

View File

@ -7,44 +7,44 @@ import "fmt"
import "time" import "time"
func main() { func main() {
p := fmt.Println p := fmt.Println
// Here's a basic example of formatting a time // Here's a basic example of formatting a time
// according to RFC3339, using the corresponding layout // according to RFC3339, using the corresponding layout
// constant. // constant.
t := time.Now() t := time.Now()
p(t.Format(time.RFC3339)) p(t.Format(time.RFC3339))
// Time parsing uses the same layout values as `Format`. // Time parsing uses the same layout values as `Format`.
t1, e := time.Parse( t1, e := time.Parse(
time.RFC3339, time.RFC3339,
"2012-11-01T22:08:41+00:00") "2012-11-01T22:08:41+00:00")
p(t1) p(t1)
// `Format` and `Parse` use example-based layouts. Usually // `Format` and `Parse` use example-based layouts. Usually
// you'll use a constant from `time` for these layouts, but // you'll use a constant from `time` for these layouts, but
// you can also supply custom layouts. Layouts must use the // you can also supply custom layouts. Layouts must use the
// reference time `Mon Jan 2 15:04:05 MST 2006` to show the // reference time `Mon Jan 2 15:04:05 MST 2006` to show the
// pattern with which to format/parse a given time/string. // pattern with which to format/parse a given time/string.
// The example time must be exactly as shown: the year 2006, // The example time must be exactly as shown: the year 2006,
// 15 for the hour, Monday for the day of the week, etc. // 15 for the hour, Monday for the day of the week, etc.
p(t.Format("3:04PM")) p(t.Format("3:04PM"))
p(t.Format("Mon Jan _2 15:04:05 2006")) p(t.Format("Mon Jan _2 15:04:05 2006"))
p(t.Format("2006-01-02T15:04:05.999999-07:00")) p(t.Format("2006-01-02T15:04:05.999999-07:00"))
form := "3 04 PM" form := "3 04 PM"
t2, e := time.Parse(form, "8 41 PM") t2, e := time.Parse(form, "8 41 PM")
p(t2) p(t2)
// For purely numeric representations you can also // For purely numeric representations you can also
// use standard string formatting with the extracted // use standard string formatting with the extracted
// components of the time value. // components of the time value.
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n", fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
t.Year(), t.Month(), t.Day(), t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second()) t.Hour(), t.Minute(), t.Second())
// `Parse` will return an error on malformed input // `Parse` will return an error on malformed input
// explaining the parsing problem. // explaining the parsing problem.
ansic := "Mon Jan _2 15:04:05 2006" ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM") _, e = time.Parse(ansic, "8:41PM")
p(e) p(e)
} }

View File

@ -1,2 +1,2 @@
1f9962260f5c92efe57db0b96099b3dd06c90333 1f9962260f5c92efe57db0b96099b3dd06c90333
BFw556nWcM nHAisH6amZG

View File

@ -7,55 +7,55 @@ import "fmt"
import "time" import "time"
func main() { func main() {
p := fmt.Println p := fmt.Println
// We'll start by getting the current time. // We'll start by getting the current time.
now := time.Now() now := time.Now()
p(now) p(now)
// You can build a `time` struct by providing the // You can build a `time` struct by providing the
// year, month, day, etc. Times are always associated // year, month, day, etc. Times are always associated
// with a `Location`, i.e. time zone. // with a `Location`, i.e. time zone.
then := time.Date( then := time.Date(
2009, 11, 17, 20, 34, 58, 651387237, time.UTC) 2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
p(then) p(then)
// You can extract the various components of the time // You can extract the various components of the time
// value as expected. // value as expected.
p(then.Year()) p(then.Year())
p(then.Month()) p(then.Month())
p(then.Day()) p(then.Day())
p(then.Hour()) p(then.Hour())
p(then.Minute()) p(then.Minute())
p(then.Second()) p(then.Second())
p(then.Nanosecond()) p(then.Nanosecond())
p(then.Location()) p(then.Location())
// The Monday-Sunday `Weekday` is also available. // The Monday-Sunday `Weekday` is also available.
p(then.Weekday()) p(then.Weekday())
// These methods compare two times, testing if the // These methods compare two times, testing if the
// first occurs before, after, or at the same time // first occurs before, after, or at the same time
// as the second, respectively. // as the second, respectively.
p(then.Before(now)) p(then.Before(now))
p(then.After(now)) p(then.After(now))
p(then.Equal(now)) p(then.Equal(now))
// The `Sub` methods returns a `Duration` representing // The `Sub` methods returns a `Duration` representing
// the interval between two times. // the interval between two times.
diff := now.Sub(then) diff := now.Sub(then)
p(diff) p(diff)
// We can compute the length of the duration in // We can compute the length of the duration in
// various units. // various units.
p(diff.Hours()) p(diff.Hours())
p(diff.Minutes()) p(diff.Minutes())
p(diff.Seconds()) p(diff.Seconds())
p(diff.Nanoseconds()) p(diff.Nanoseconds())
// You can use `Add` to advance a time by a given // You can use `Add` to advance a time by a given
// duration, or with a `-` to move backwards by a // duration, or with a `-` to move backwards by a
// duration. // duration.
p(then.Add(diff)) p(then.Add(diff))
p(then.Add(-diff)) p(then.Add(-diff))
} }

View File

@ -1,2 +1,2 @@
b6308f1fea7665e89a28f54aac6cb49b95685eb5 b6308f1fea7665e89a28f54aac6cb49b95685eb5
TTYPzggHg0 PZMCzzaJURJ

View File

@ -10,39 +10,39 @@ import "fmt"
func main() { func main() {
// For our example, suppose we're executing an external // For our example, suppose we're executing an external
// call that returns its result on a channel `c1` // call that returns its result on a channel `c1`
// after 2s. // after 2s.
c1 := make(chan string, 1) c1 := make(chan string, 1)
go func() { go func() {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
c1 <- "result 1" c1 <- "result 1"
}() }()
// Here's the `select` implementing a timeout. // Here's the `select` implementing a timeout.
// `res := <-c1` awaits the result and `<-Time.After` // `res := <-c1` awaits the result and `<-Time.After`
// awaits a value to be sent after the timeout of // awaits a value to be sent after the timeout of
// 1s. Since `select` proceeds with the first // 1s. Since `select` proceeds with the first
// receive that's ready, we'll take the timeout case // receive that's ready, we'll take the timeout case
// if the operation takes more than the allowed 1s. // if the operation takes more than the allowed 1s.
select { select {
case res := <-c1: case res := <-c1:
fmt.Println(res) fmt.Println(res)
case <-time.After(1 * time.Second): case <-time.After(1 * time.Second):
fmt.Println("timeout 1") fmt.Println("timeout 1")
} }
// If we allow a longer timeout of 3s, then the receive // If we allow a longer timeout of 3s, then the receive
// from `c2` will succeed and we'll print the result. // from `c2` will succeed and we'll print the result.
c2 := make(chan string, 1) c2 := make(chan string, 1)
go func() { go func() {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
c2 <- "result 2" c2 <- "result 2"
}() }()
select { select {
case res := <-c2: case res := <-c2:
fmt.Println(res) fmt.Println(res)
case <-time.After(3 * time.Second): case <-time.After(3 * time.Second):
fmt.Println("timeout 2") fmt.Println("timeout 2")
} }
} }

View File

@ -11,29 +11,29 @@ import "fmt"
func main() { func main() {
// Timers represent a single event in the future. You // Timers represent a single event in the future. You
// tell the timer how long you want to wait, and it // tell the timer how long you want to wait, and it
// provides a channel that will be notified at that // provides a channel that will be notified at that
// time. This timer will wait 2 seconds. // time. This timer will wait 2 seconds.
timer1 := time.NewTimer(2 * time.Second) timer1 := time.NewTimer(2 * time.Second)
// The `<-timer1.C` blocks on the timer's channel `C` // The `<-timer1.C` blocks on the timer's channel `C`
// until it sends a value indicating that the timer // until it sends a value indicating that the timer
// expired. // expired.
<-timer1.C <-timer1.C
fmt.Println("Timer 1 expired") fmt.Println("Timer 1 expired")
// If you just wanted to wait, you could have used // If you just wanted to wait, you could have used
// `time.Sleep`. One reason a timer may be useful is // `time.Sleep`. One reason a timer may be useful is
// that you can cancel the timer before it expires. // that you can cancel the timer before it expires.
// Here's an example of that. // Here's an example of that.
timer2 := time.NewTimer(time.Second) timer2 := time.NewTimer(time.Second)
go func() { go func() {
<-timer2.C <-timer2.C
fmt.Println("Timer 2 expired") fmt.Println("Timer 2 expired")
}() }()
stop2 := timer2.Stop() stop2 := timer2.Stop()
if stop2 { if stop2 {
fmt.Println("Timer 2 stopped") fmt.Println("Timer 2 stopped")
} }
} }

View File

@ -9,47 +9,47 @@ import "net/url"
func main() { func main() {
// We'll parse this example URL, which includes a // We'll parse this example URL, which includes a
// scheme, authentication info, host, port, path, // scheme, authentication info, host, port, path,
// query params, and query fragment. // query params, and query fragment.
s := "postgres://user:pass@host.com:5432/path?k=v#f" s := "postgres://user:pass@host.com:5432/path?k=v#f"
// Parse the URL and ensure there are no errors. // Parse the URL and ensure there are no errors.
u, err := url.Parse(s) u, err := url.Parse(s)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Accessing the scheme is straightforward. // Accessing the scheme is straightforward.
fmt.Println(u.Scheme) fmt.Println(u.Scheme)
// `User` contains all authentication info; call // `User` contains all authentication info; call
// `Username` and `Password` on this for individual // `Username` and `Password` on this for individual
// values. // values.
fmt.Println(u.User) fmt.Println(u.User)
fmt.Println(u.User.Username()) fmt.Println(u.User.Username())
p, _ := u.User.Password() p, _ := u.User.Password()
fmt.Println(p) fmt.Println(p)
// The `Host` contains both the hostname and the port, // The `Host` contains both the hostname and the port,
// if present. Use `SplitHostPort` to extract them. // if present. Use `SplitHostPort` to extract them.
fmt.Println(u.Host) fmt.Println(u.Host)
host, port, _ := net.SplitHostPort(u.Host) host, port, _ := net.SplitHostPort(u.Host)
fmt.Println(host) fmt.Println(host)
fmt.Println(port) fmt.Println(port)
// Here we extract the `path` and the fragment after // Here we extract the `path` and the fragment after
// the `#`. // the `#`.
fmt.Println(u.Path) fmt.Println(u.Path)
fmt.Println(u.Fragment) fmt.Println(u.Fragment)
// To get query params in a string of `k=v` format, // To get query params in a string of `k=v` format,
// use `RawQuery`. You can also parse query params // use `RawQuery`. You can also parse query params
// into a map. The parsed query param maps are from // into a map. The parsed query param maps are from
// strings to slices of strings, so index into `[0]` // strings to slices of strings, so index into `[0]`
// if you only want the first value. // if you only want the first value.
fmt.Println(u.RawQuery) fmt.Println(u.RawQuery)
m, _ := url.ParseQuery(u.RawQuery) m, _ := url.ParseQuery(u.RawQuery)
fmt.Println(m) fmt.Println(m)
fmt.Println(m["k"][0]) fmt.Println(m["k"][0])
} }

View File

@ -8,15 +8,15 @@ import "fmt"
func main() { func main() {
// Strings, which can be added together with `+`. // Strings, which can be added together with `+`.
fmt.Println("go" + "lang") fmt.Println("go" + "lang")
// Integers and floats. // Integers and floats.
fmt.Println("1+1 =", 1+1) fmt.Println("1+1 =", 1+1)
fmt.Println("7.0/3.0 =", 7.0/3.0) fmt.Println("7.0/3.0 =", 7.0/3.0)
// Booleans, with boolean operators as you'd expect. // Booleans, with boolean operators as you'd expect.
fmt.Println(true && false) fmt.Println(true && false)
fmt.Println(true || false) fmt.Println(true || false)
fmt.Println(!true) fmt.Println(!true)
} }

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