Use tabs as the canonical source indentation in git
Space conversion is done during generation only. Fixes #192
This commit is contained in:
parent
1699ad1c45
commit
7c160440be
@ -7,36 +7,36 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here we create an array `a` that will hold exactly
|
||||
// 5 `int`s. The type of elements and length are both
|
||||
// part of the array's type. By default an array is
|
||||
// zero-valued, which for `int`s means `0`s.
|
||||
var a [5]int
|
||||
fmt.Println("emp:", a)
|
||||
// Here we create an array `a` that will hold exactly
|
||||
// 5 `int`s. The type of elements and length are both
|
||||
// part of the array's type. By default an array is
|
||||
// zero-valued, which for `int`s means `0`s.
|
||||
var a [5]int
|
||||
fmt.Println("emp:", a)
|
||||
|
||||
// We can set a value at an index using the
|
||||
// `array[index] = value` syntax, and get a value with
|
||||
// `array[index]`.
|
||||
a[4] = 100
|
||||
fmt.Println("set:", a)
|
||||
fmt.Println("get:", a[4])
|
||||
// We can set a value at an index using the
|
||||
// `array[index] = value` syntax, and get a value with
|
||||
// `array[index]`.
|
||||
a[4] = 100
|
||||
fmt.Println("set:", a)
|
||||
fmt.Println("get:", a[4])
|
||||
|
||||
// The builtin `len` returns the length of an array.
|
||||
fmt.Println("len:", len(a))
|
||||
// The builtin `len` returns the length of an array.
|
||||
fmt.Println("len:", len(a))
|
||||
|
||||
// Use this syntax to declare and initialize an array
|
||||
// in one line.
|
||||
b := [5]int{1, 2, 3, 4, 5}
|
||||
fmt.Println("dcl:", b)
|
||||
// Use this syntax to declare and initialize an array
|
||||
// in one line.
|
||||
b := [5]int{1, 2, 3, 4, 5}
|
||||
fmt.Println("dcl:", b)
|
||||
|
||||
// Array types are one-dimensional, but you can
|
||||
// compose types to build multi-dimensional data
|
||||
// structures.
|
||||
var twoD [2][3]int
|
||||
for i := 0; i < 2; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
twoD[i][j] = i + j
|
||||
}
|
||||
}
|
||||
fmt.Println("2d: ", twoD)
|
||||
// Array types are one-dimensional, but you can
|
||||
// compose types to build multi-dimensional data
|
||||
// structures.
|
||||
var twoD [2][3]int
|
||||
for i := 0; i < 2; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
twoD[i][j] = i + j
|
||||
}
|
||||
}
|
||||
fmt.Println("2d: ", twoD)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
305975d13d24223181d13f042b290906d86c1a0e
|
||||
l-A8eBnwio
|
||||
W7NwfDq8Vdw
|
||||
|
@ -13,37 +13,37 @@ import "sync/atomic"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll use an unsigned integer to represent our
|
||||
// (always-positive) counter.
|
||||
var ops uint64
|
||||
// We'll use an unsigned integer to represent our
|
||||
// (always-positive) counter.
|
||||
var ops uint64
|
||||
|
||||
// To simulate concurrent updates, we'll start 50
|
||||
// goroutines that each increment the counter about
|
||||
// once a millisecond.
|
||||
for i := 0; i < 50; i++ {
|
||||
go func() {
|
||||
for {
|
||||
// To atomically increment the counter we
|
||||
// use `AddUint64`, giving it the memory
|
||||
// address of our `ops` counter with the
|
||||
// `&` syntax.
|
||||
atomic.AddUint64(&ops, 1)
|
||||
// To simulate concurrent updates, we'll start 50
|
||||
// goroutines that each increment the counter about
|
||||
// once a millisecond.
|
||||
for i := 0; i < 50; i++ {
|
||||
go func() {
|
||||
for {
|
||||
// To atomically increment the counter we
|
||||
// use `AddUint64`, giving it the memory
|
||||
// address of our `ops` counter with the
|
||||
// `&` syntax.
|
||||
atomic.AddUint64(&ops, 1)
|
||||
|
||||
// Wait a bit between increments.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Wait a bit between increments.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait a second to allow some ops to accumulate.
|
||||
time.Sleep(time.Second)
|
||||
// Wait a second to allow some ops to accumulate.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// In order to safely use the counter while it's still
|
||||
// being updated by other goroutines, we extract a
|
||||
// copy of the current value into `opsFinal` via
|
||||
// `LoadUint64`. As above we need to give this
|
||||
// function the memory address `&ops` from which to
|
||||
// fetch the value.
|
||||
opsFinal := atomic.LoadUint64(&ops)
|
||||
fmt.Println("ops:", opsFinal)
|
||||
// In order to safely use the counter while it's still
|
||||
// being updated by other goroutines, we extract a
|
||||
// copy of the current value into `opsFinal` via
|
||||
// `LoadUint64`. As above we need to give this
|
||||
// function the memory address `&ops` from which to
|
||||
// fetch the value.
|
||||
opsFinal := atomic.LoadUint64(&ops)
|
||||
fmt.Println("ops:", opsFinal)
|
||||
}
|
||||
|
@ -11,27 +11,27 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here's the `string` we'll encode/decode.
|
||||
data := "abc123!?$*&()'-=@~"
|
||||
// Here's the `string` we'll encode/decode.
|
||||
data := "abc123!?$*&()'-=@~"
|
||||
|
||||
// Go supports both standard and URL-compatible
|
||||
// base64. Here's how to encode using the standard
|
||||
// encoder. The encoder requires a `[]byte` so we
|
||||
// convert our `string` to that type.
|
||||
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
|
||||
fmt.Println(sEnc)
|
||||
// Go supports both standard and URL-compatible
|
||||
// base64. Here's how to encode using the standard
|
||||
// encoder. The encoder requires a `[]byte` so we
|
||||
// convert our `string` to that type.
|
||||
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
|
||||
fmt.Println(sEnc)
|
||||
|
||||
// Decoding may return an error, which you can check
|
||||
// if you don't already know the input to be
|
||||
// well-formed.
|
||||
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
|
||||
fmt.Println(string(sDec))
|
||||
fmt.Println()
|
||||
// Decoding may return an error, which you can check
|
||||
// if you don't already know the input to be
|
||||
// well-formed.
|
||||
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
|
||||
fmt.Println(string(sDec))
|
||||
fmt.Println()
|
||||
|
||||
// This encodes/decodes using a URL-compatible base64
|
||||
// format.
|
||||
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
|
||||
fmt.Println(uEnc)
|
||||
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
|
||||
fmt.Println(string(uDec))
|
||||
// This encodes/decodes using a URL-compatible base64
|
||||
// format.
|
||||
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
|
||||
fmt.Println(uEnc)
|
||||
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
|
||||
fmt.Println(string(uDec))
|
||||
}
|
||||
|
@ -11,17 +11,17 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here we `make` a channel of strings buffering up to
|
||||
// 2 values.
|
||||
messages := make(chan string, 2)
|
||||
// Here we `make` a channel of strings buffering up to
|
||||
// 2 values.
|
||||
messages := make(chan string, 2)
|
||||
|
||||
// Because this channel is buffered, we can send these
|
||||
// values into the channel without a corresponding
|
||||
// concurrent receive.
|
||||
messages <- "buffered"
|
||||
messages <- "channel"
|
||||
// Because this channel is buffered, we can send these
|
||||
// values into the channel without a corresponding
|
||||
// concurrent receive.
|
||||
messages <- "buffered"
|
||||
messages <- "channel"
|
||||
|
||||
// Later we can receive these two values as usual.
|
||||
fmt.Println(<-messages)
|
||||
fmt.Println(<-messages)
|
||||
// Later we can receive these two values as usual.
|
||||
fmt.Println(<-messages)
|
||||
fmt.Println(<-messages)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
122140f7ad1bc5cff4fcd7a9e7245b87aaca3ec5
|
||||
34PVHwO6Bn
|
||||
mPoF-Xi-rip
|
||||
|
@ -11,20 +11,20 @@ import "fmt"
|
||||
// values. It would be a compile-time error to try to
|
||||
// receive on this channel.
|
||||
func ping(pings chan<- string, msg string) {
|
||||
pings <- msg
|
||||
pings <- msg
|
||||
}
|
||||
|
||||
// The `pong` function accepts one channel for receives
|
||||
// (`pings`) and a second for sends (`pongs`).
|
||||
func pong(pings <-chan string, pongs chan<- string) {
|
||||
msg := <-pings
|
||||
pongs <- msg
|
||||
msg := <-pings
|
||||
pongs <- msg
|
||||
}
|
||||
|
||||
func main() {
|
||||
pings := make(chan string, 1)
|
||||
pongs := make(chan string, 1)
|
||||
ping(pings, "passed message")
|
||||
pong(pings, pongs)
|
||||
fmt.Println(<-pongs)
|
||||
pings := make(chan string, 1)
|
||||
pongs := make(chan string, 1)
|
||||
ping(pings, "passed message")
|
||||
pong(pings, pongs)
|
||||
fmt.Println(<-pongs)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
635cc13dfe33123ac188e01e3002d3aa935d765f
|
||||
P9Fujfpa1f
|
||||
Jnn9_9hC48c
|
||||
|
@ -13,22 +13,22 @@ import "time"
|
||||
// `done` channel will be used to notify another
|
||||
// goroutine that this function's work is done.
|
||||
func worker(done chan bool) {
|
||||
fmt.Print("working...")
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("done")
|
||||
fmt.Print("working...")
|
||||
time.Sleep(time.Second)
|
||||
fmt.Println("done")
|
||||
|
||||
// Send a value to notify that we're done.
|
||||
done <- true
|
||||
// Send a value to notify that we're done.
|
||||
done <- true
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Start a worker goroutine, giving it the channel to
|
||||
// notify on.
|
||||
done := make(chan bool, 1)
|
||||
go worker(done)
|
||||
// Start a worker goroutine, giving it the channel to
|
||||
// notify on.
|
||||
done := make(chan bool, 1)
|
||||
go worker(done)
|
||||
|
||||
// Block until we receive a notification from the
|
||||
// worker on the channel.
|
||||
<-done
|
||||
// Block until we receive a notification from the
|
||||
// worker on the channel.
|
||||
<-done
|
||||
}
|
||||
|
@ -9,18 +9,18 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Create a new channel with `make(chan val-type)`.
|
||||
// Channels are typed by the values they convey.
|
||||
messages := make(chan string)
|
||||
// Create a new channel with `make(chan val-type)`.
|
||||
// Channels are typed by the values they convey.
|
||||
messages := make(chan string)
|
||||
|
||||
// _Send_ a value into a channel using the `channel <-`
|
||||
// syntax. Here we send `"ping"` to the `messages`
|
||||
// channel we made above, from a new goroutine.
|
||||
go func() { messages <- "ping" }()
|
||||
// _Send_ a value into a channel using the `channel <-`
|
||||
// syntax. Here we send `"ping"` to the `messages`
|
||||
// channel we made above, from a new goroutine.
|
||||
go func() { messages <- "ping" }()
|
||||
|
||||
// The `<-channel` syntax _receives_ a value from the
|
||||
// channel. Here we'll receive the `"ping"` message
|
||||
// we sent above and print it out.
|
||||
msg := <-messages
|
||||
fmt.Println(msg)
|
||||
// The `<-channel` syntax _receives_ a value from the
|
||||
// channel. Here we'll receive the `"ping"` message
|
||||
// we sent above and print it out.
|
||||
msg := <-messages
|
||||
fmt.Println(msg)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
926212c784ab820648906c96f6ab21afbc161526
|
||||
Kd8B0T_JGK
|
||||
bRGMAqinovA
|
||||
|
@ -11,40 +11,40 @@ import "fmt"
|
||||
// to a worker goroutine. When we have no more jobs for
|
||||
// the worker we'll `close` the `jobs` channel.
|
||||
func main() {
|
||||
jobs := make(chan int, 5)
|
||||
done := make(chan bool)
|
||||
jobs := make(chan int, 5)
|
||||
done := make(chan bool)
|
||||
|
||||
// Here's the worker goroutine. It repeatedly receives
|
||||
// from `jobs` with `j, more := <-jobs`. In this
|
||||
// special 2-value form of receive, the `more` value
|
||||
// will be `false` if `jobs` has been `close`d and all
|
||||
// values in the channel have already been received.
|
||||
// We use this to notify on `done` when we've worked
|
||||
// all our jobs.
|
||||
go func() {
|
||||
for {
|
||||
j, more := <-jobs
|
||||
if more {
|
||||
fmt.Println("received job", j)
|
||||
} else {
|
||||
fmt.Println("received all jobs")
|
||||
done <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
// Here's the worker goroutine. It repeatedly receives
|
||||
// from `jobs` with `j, more := <-jobs`. In this
|
||||
// special 2-value form of receive, the `more` value
|
||||
// will be `false` if `jobs` has been `close`d and all
|
||||
// values in the channel have already been received.
|
||||
// We use this to notify on `done` when we've worked
|
||||
// all our jobs.
|
||||
go func() {
|
||||
for {
|
||||
j, more := <-jobs
|
||||
if more {
|
||||
fmt.Println("received job", j)
|
||||
} else {
|
||||
fmt.Println("received all jobs")
|
||||
done <- true
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// This sends 3 jobs to the worker over the `jobs`
|
||||
// channel, then closes it.
|
||||
for j := 1; j <= 3; j++ {
|
||||
jobs <- j
|
||||
fmt.Println("sent job", j)
|
||||
}
|
||||
close(jobs)
|
||||
fmt.Println("sent all jobs")
|
||||
// This sends 3 jobs to the worker over the `jobs`
|
||||
// channel, then closes it.
|
||||
for j := 1; j <= 3; j++ {
|
||||
jobs <- j
|
||||
fmt.Println("sent job", j)
|
||||
}
|
||||
close(jobs)
|
||||
fmt.Println("sent all jobs")
|
||||
|
||||
// We await the worker using the
|
||||
// [synchronization](channel-synchronization) approach
|
||||
// we saw earlier.
|
||||
<-done
|
||||
// We await the worker using the
|
||||
// [synchronization](channel-synchronization) approach
|
||||
// we saw earlier.
|
||||
<-done
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
5205898a520533e46ea24c849848d19ebc2d08a9
|
||||
eFZ2SeKswH
|
||||
mkz69rVMHs6
|
||||
|
@ -12,29 +12,29 @@ import "fmt"
|
||||
// returned function _closes over_ the variable `i` to
|
||||
// form a closure.
|
||||
func intSeq() func() int {
|
||||
i := 0
|
||||
return func() int {
|
||||
i++
|
||||
return i
|
||||
}
|
||||
i := 0
|
||||
return func() int {
|
||||
i++
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// We call `intSeq`, assigning the result (a function)
|
||||
// to `nextInt`. This function value captures its
|
||||
// own `i` value, which will be updated each time
|
||||
// we call `nextInt`.
|
||||
nextInt := intSeq()
|
||||
// We call `intSeq`, assigning the result (a function)
|
||||
// to `nextInt`. This function value captures its
|
||||
// own `i` value, which will be updated each time
|
||||
// we call `nextInt`.
|
||||
nextInt := intSeq()
|
||||
|
||||
// See the effect of the closure by calling `nextInt`
|
||||
// a few times.
|
||||
fmt.Println(nextInt())
|
||||
fmt.Println(nextInt())
|
||||
fmt.Println(nextInt())
|
||||
// See the effect of the closure by calling `nextInt`
|
||||
// a few times.
|
||||
fmt.Println(nextInt())
|
||||
fmt.Println(nextInt())
|
||||
fmt.Println(nextInt())
|
||||
|
||||
// To confirm that the state is unique to that
|
||||
// particular function, create and test a new one.
|
||||
newInts := intSeq()
|
||||
fmt.Println(newInts())
|
||||
// To confirm that the state is unique to that
|
||||
// particular function, create and test a new one.
|
||||
newInts := intSeq()
|
||||
fmt.Println(newInts())
|
||||
}
|
||||
|
@ -24,88 +24,88 @@ import "fmt"
|
||||
// Index returns the first index of the target string `t`, or
|
||||
// -1 if no match is found.
|
||||
func Index(vs []string, t string) int {
|
||||
for i, v := range vs {
|
||||
if v == t {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
for i, v := range vs {
|
||||
if v == t {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Include returns `true` if the target string t is in the
|
||||
// slice.
|
||||
func Include(vs []string, t string) bool {
|
||||
return Index(vs, t) >= 0
|
||||
return Index(vs, t) >= 0
|
||||
}
|
||||
|
||||
// Any returns `true` if one of the strings in the slice
|
||||
// satisfies the predicate `f`.
|
||||
func Any(vs []string, f func(string) bool) bool {
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// All returns `true` if all of the strings in the slice
|
||||
// satisfy the predicate `f`.
|
||||
func All(vs []string, f func(string) bool) bool {
|
||||
for _, v := range vs {
|
||||
if !f(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
for _, v := range vs {
|
||||
if !f(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Filter returns a new slice containing all strings in the
|
||||
// slice that satisfy the predicate `f`.
|
||||
func Filter(vs []string, f func(string) bool) []string {
|
||||
vsf := make([]string, 0)
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
vsf = append(vsf, v)
|
||||
}
|
||||
}
|
||||
return vsf
|
||||
vsf := make([]string, 0)
|
||||
for _, v := range vs {
|
||||
if f(v) {
|
||||
vsf = append(vsf, v)
|
||||
}
|
||||
}
|
||||
return vsf
|
||||
}
|
||||
|
||||
// Map returns a new slice containing the results of applying
|
||||
// the function `f` to each string in the original slice.
|
||||
func Map(vs []string, f func(string) string) []string {
|
||||
vsm := make([]string, len(vs))
|
||||
for i, v := range vs {
|
||||
vsm[i] = f(v)
|
||||
}
|
||||
return vsm
|
||||
vsm := make([]string, len(vs))
|
||||
for i, v := range vs {
|
||||
vsm[i] = f(v)
|
||||
}
|
||||
return vsm
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Here we try out our various collection functions.
|
||||
var strs = []string{"peach", "apple", "pear", "plum"}
|
||||
// Here we try out our various collection functions.
|
||||
var strs = []string{"peach", "apple", "pear", "plum"}
|
||||
|
||||
fmt.Println(Index(strs, "pear"))
|
||||
fmt.Println(Index(strs, "pear"))
|
||||
|
||||
fmt.Println(Include(strs, "grape"))
|
||||
fmt.Println(Include(strs, "grape"))
|
||||
|
||||
fmt.Println(Any(strs, func(v string) bool {
|
||||
return strings.HasPrefix(v, "p")
|
||||
}))
|
||||
fmt.Println(Any(strs, func(v string) bool {
|
||||
return strings.HasPrefix(v, "p")
|
||||
}))
|
||||
|
||||
fmt.Println(All(strs, func(v string) bool {
|
||||
return strings.HasPrefix(v, "p")
|
||||
}))
|
||||
fmt.Println(All(strs, func(v string) bool {
|
||||
return strings.HasPrefix(v, "p")
|
||||
}))
|
||||
|
||||
fmt.Println(Filter(strs, func(v string) bool {
|
||||
return strings.Contains(v, "e")
|
||||
}))
|
||||
fmt.Println(Filter(strs, func(v string) bool {
|
||||
return strings.Contains(v, "e")
|
||||
}))
|
||||
|
||||
// The above examples all used anonymous functions,
|
||||
// but you can also use named functions of the correct
|
||||
// type.
|
||||
fmt.Println(Map(strs, strings.ToUpper))
|
||||
// The above examples all used anonymous functions,
|
||||
// but you can also use named functions of the correct
|
||||
// type.
|
||||
fmt.Println(Map(strs, strings.ToUpper))
|
||||
|
||||
}
|
||||
|
@ -10,17 +10,17 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// `os.Args` provides access to raw command-line
|
||||
// arguments. Note that the first value in this slice
|
||||
// is the path to the program, and `os.Args[1:]`
|
||||
// holds the arguments to the program.
|
||||
argsWithProg := os.Args
|
||||
argsWithoutProg := os.Args[1:]
|
||||
// `os.Args` provides access to raw command-line
|
||||
// arguments. Note that the first value in this slice
|
||||
// is the path to the program, and `os.Args[1:]`
|
||||
// holds the arguments to the program.
|
||||
argsWithProg := os.Args
|
||||
argsWithoutProg := os.Args[1:]
|
||||
|
||||
// You can get individual args with normal indexing.
|
||||
arg := os.Args[3]
|
||||
// You can get individual args with normal indexing.
|
||||
arg := os.Args[3]
|
||||
|
||||
fmt.Println(argsWithProg)
|
||||
fmt.Println(argsWithoutProg)
|
||||
fmt.Println(arg)
|
||||
fmt.Println(argsWithProg)
|
||||
fmt.Println(argsWithoutProg)
|
||||
fmt.Println(arg)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
41c970a1ef29ad2a05307e6c783ff52ab80eaccd
|
||||
44uyYt_TRl
|
||||
6pFdjf800jj
|
||||
|
@ -13,37 +13,37 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Basic flag declarations are available for string,
|
||||
// integer, and boolean options. Here we declare a
|
||||
// string flag `word` with a default value `"foo"`
|
||||
// and a short description. This `flag.String` function
|
||||
// returns a string pointer (not a string value);
|
||||
// we'll see how to use this pointer below.
|
||||
wordPtr := flag.String("word", "foo", "a string")
|
||||
// Basic flag declarations are available for string,
|
||||
// integer, and boolean options. Here we declare a
|
||||
// string flag `word` with a default value `"foo"`
|
||||
// and a short description. This `flag.String` function
|
||||
// returns a string pointer (not a string value);
|
||||
// we'll see how to use this pointer below.
|
||||
wordPtr := flag.String("word", "foo", "a string")
|
||||
|
||||
// This declares `numb` and `fork` flags, using a
|
||||
// similar approach to the `word` flag.
|
||||
numbPtr := flag.Int("numb", 42, "an int")
|
||||
boolPtr := flag.Bool("fork", false, "a bool")
|
||||
// This declares `numb` and `fork` flags, using a
|
||||
// similar approach to the `word` flag.
|
||||
numbPtr := flag.Int("numb", 42, "an int")
|
||||
boolPtr := flag.Bool("fork", false, "a bool")
|
||||
|
||||
// It's also possible to declare an option that uses an
|
||||
// existing var declared elsewhere in the program.
|
||||
// Note that we need to pass in a pointer to the flag
|
||||
// declaration function.
|
||||
var svar string
|
||||
flag.StringVar(&svar, "svar", "bar", "a string var")
|
||||
// It's also possible to declare an option that uses an
|
||||
// existing var declared elsewhere in the program.
|
||||
// Note that we need to pass in a pointer to the flag
|
||||
// declaration function.
|
||||
var svar string
|
||||
flag.StringVar(&svar, "svar", "bar", "a string var")
|
||||
|
||||
// Once all flags are declared, call `flag.Parse()`
|
||||
// to execute the command-line parsing.
|
||||
flag.Parse()
|
||||
// Once all flags are declared, call `flag.Parse()`
|
||||
// to execute the command-line parsing.
|
||||
flag.Parse()
|
||||
|
||||
// Here we'll just dump out the parsed options and
|
||||
// any trailing positional arguments. Note that we
|
||||
// need to dereference the pointers with e.g. `*wordPtr`
|
||||
// to get the actual option values.
|
||||
fmt.Println("word:", *wordPtr)
|
||||
fmt.Println("numb:", *numbPtr)
|
||||
fmt.Println("fork:", *boolPtr)
|
||||
fmt.Println("svar:", svar)
|
||||
fmt.Println("tail:", flag.Args())
|
||||
// Here we'll just dump out the parsed options and
|
||||
// any trailing positional arguments. Note that we
|
||||
// need to dereference the pointers with e.g. `*wordPtr`
|
||||
// to get the actual option values.
|
||||
fmt.Println("word:", *wordPtr)
|
||||
fmt.Println("numb:", *numbPtr)
|
||||
fmt.Println("fork:", *boolPtr)
|
||||
fmt.Println("svar:", svar)
|
||||
fmt.Println("tail:", flag.Args())
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
e2ba0461c090789168c712cc7ed0f66aab09a8c8
|
||||
NASEOq2R3n
|
||||
klFR5DitrCy
|
||||
|
@ -10,24 +10,24 @@ import "math"
|
||||
const s string = "constant"
|
||||
|
||||
func main() {
|
||||
fmt.Println(s)
|
||||
fmt.Println(s)
|
||||
|
||||
// A `const` statement can appear anywhere a `var`
|
||||
// statement can.
|
||||
const n = 500000000
|
||||
// A `const` statement can appear anywhere a `var`
|
||||
// statement can.
|
||||
const n = 500000000
|
||||
|
||||
// Constant expressions perform arithmetic with
|
||||
// arbitrary precision.
|
||||
const d = 3e20 / n
|
||||
fmt.Println(d)
|
||||
// Constant expressions perform arithmetic with
|
||||
// arbitrary precision.
|
||||
const d = 3e20 / n
|
||||
fmt.Println(d)
|
||||
|
||||
// A numeric constant has no type until it's given
|
||||
// one, such as by an explicit conversion.
|
||||
fmt.Println(int64(d))
|
||||
// A numeric constant has no type until it's given
|
||||
// one, such as by an explicit conversion.
|
||||
fmt.Println(int64(d))
|
||||
|
||||
// A number can be given a type by using it in a
|
||||
// context that requires one, such as a variable
|
||||
// assignment or function call. For example, here
|
||||
// `math.Sin` expects a `float64`.
|
||||
fmt.Println(math.Sin(n))
|
||||
// A number can be given a type by using it in a
|
||||
// context that requires one, such as a variable
|
||||
// assignment or function call. For example, here
|
||||
// `math.Sin` expects a `float64`.
|
||||
fmt.Println(math.Sin(n))
|
||||
}
|
||||
|
@ -13,32 +13,32 @@ import "os"
|
||||
// do that with `defer`.
|
||||
func main() {
|
||||
|
||||
// Immediately after getting a file object with
|
||||
// `createFile`, we defer the closing of that file
|
||||
// with `closeFile`. This will be executed at the end
|
||||
// of the enclosing function (`main`), after
|
||||
// `writeFile` has finished.
|
||||
f := createFile("/tmp/defer.txt")
|
||||
defer closeFile(f)
|
||||
writeFile(f)
|
||||
// Immediately after getting a file object with
|
||||
// `createFile`, we defer the closing of that file
|
||||
// with `closeFile`. This will be executed at the end
|
||||
// of the enclosing function (`main`), after
|
||||
// `writeFile` has finished.
|
||||
f := createFile("/tmp/defer.txt")
|
||||
defer closeFile(f)
|
||||
writeFile(f)
|
||||
}
|
||||
|
||||
func createFile(p string) *os.File {
|
||||
fmt.Println("creating")
|
||||
f, err := os.Create(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return f
|
||||
fmt.Println("creating")
|
||||
f, err := os.Create(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func writeFile(f *os.File) {
|
||||
fmt.Println("writing")
|
||||
fmt.Fprintln(f, "data")
|
||||
fmt.Println("writing")
|
||||
fmt.Fprintln(f, "data")
|
||||
|
||||
}
|
||||
|
||||
func closeFile(f *os.File) {
|
||||
fmt.Println("closing")
|
||||
f.Close()
|
||||
fmt.Println("closing")
|
||||
f.Close()
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
570699fc50a1d39e9d0ad6a4461aef3248b080e1
|
||||
9aoHwzHcAo
|
||||
xPbQ5SGkH2O
|
||||
|
@ -11,21 +11,21 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// To set a key/value pair, use `os.Setenv`. To get a
|
||||
// value for a key, use `os.Getenv`. This will return
|
||||
// an empty string if the key isn't present in the
|
||||
// environment.
|
||||
os.Setenv("FOO", "1")
|
||||
fmt.Println("FOO:", os.Getenv("FOO"))
|
||||
fmt.Println("BAR:", os.Getenv("BAR"))
|
||||
// To set a key/value pair, use `os.Setenv`. To get a
|
||||
// value for a key, use `os.Getenv`. This will return
|
||||
// an empty string if the key isn't present in the
|
||||
// environment.
|
||||
os.Setenv("FOO", "1")
|
||||
fmt.Println("FOO:", os.Getenv("FOO"))
|
||||
fmt.Println("BAR:", os.Getenv("BAR"))
|
||||
|
||||
// Use `os.Environ` to list all key/value pairs in the
|
||||
// environment. This returns a slice of strings in the
|
||||
// form `KEY=value`. You can `strings.Split` them to
|
||||
// get the key and value. Here we print all the keys.
|
||||
fmt.Println()
|
||||
for _, e := range os.Environ() {
|
||||
pair := strings.Split(e, "=")
|
||||
fmt.Println(pair[0])
|
||||
}
|
||||
// Use `os.Environ` to list all key/value pairs in the
|
||||
// environment. This returns a slice of strings in the
|
||||
// form `KEY=value`. You can `strings.Split` them to
|
||||
// get the key and value. Here we print all the keys.
|
||||
fmt.Println()
|
||||
for _, e := range os.Environ() {
|
||||
pair := strings.Split(e, "=")
|
||||
fmt.Println(pair[0])
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
4d0832c5a1ddd4e95474791e8802c15452358214
|
||||
kfqLhpmEpw
|
||||
CZJ4R_uu6Uu
|
||||
|
@ -10,24 +10,24 @@ import "time"
|
||||
|
||||
func main() {
|
||||
|
||||
// Use `time.Now` with `Unix` or `UnixNano` to get
|
||||
// elapsed time since the Unix epoch in seconds or
|
||||
// nanoseconds, respectively.
|
||||
now := time.Now()
|
||||
secs := now.Unix()
|
||||
nanos := now.UnixNano()
|
||||
fmt.Println(now)
|
||||
// Use `time.Now` with `Unix` or `UnixNano` to get
|
||||
// elapsed time since the Unix epoch in seconds or
|
||||
// nanoseconds, respectively.
|
||||
now := time.Now()
|
||||
secs := now.Unix()
|
||||
nanos := now.UnixNano()
|
||||
fmt.Println(now)
|
||||
|
||||
// Note that there is no `UnixMillis`, so to get the
|
||||
// milliseconds since epoch you'll need to manually
|
||||
// divide from nanoseconds.
|
||||
millis := nanos / 1000000
|
||||
fmt.Println(secs)
|
||||
fmt.Println(millis)
|
||||
fmt.Println(nanos)
|
||||
// Note that there is no `UnixMillis`, so to get the
|
||||
// milliseconds since epoch you'll need to manually
|
||||
// divide from nanoseconds.
|
||||
millis := nanos / 1000000
|
||||
fmt.Println(secs)
|
||||
fmt.Println(millis)
|
||||
fmt.Println(nanos)
|
||||
|
||||
// You can also convert integer seconds or nanoseconds
|
||||
// since the epoch into the corresponding `time`.
|
||||
fmt.Println(time.Unix(secs, 0))
|
||||
fmt.Println(time.Unix(0, nanos))
|
||||
// You can also convert integer seconds or nanoseconds
|
||||
// since the epoch into the corresponding `time`.
|
||||
fmt.Println(time.Unix(secs, 0))
|
||||
fmt.Println(time.Unix(0, nanos))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
61a498229c8878a97d729cfdd215e5f3960f87ac
|
||||
GP_zEjhlWk
|
||||
eN1Qv2ATB-C
|
||||
|
@ -15,17 +15,17 @@ import "fmt"
|
||||
// By convention, errors are the last return value and
|
||||
// have type `error`, a built-in interface.
|
||||
func f1(arg int) (int, error) {
|
||||
if arg == 42 {
|
||||
if arg == 42 {
|
||||
|
||||
// `errors.New` constructs a basic `error` value
|
||||
// with the given error message.
|
||||
return -1, errors.New("can't work with 42")
|
||||
// `errors.New` constructs a basic `error` value
|
||||
// with the given error message.
|
||||
return -1, errors.New("can't work with 42")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// A `nil` value in the error position indicates that
|
||||
// there was no error.
|
||||
return arg + 3, nil
|
||||
// A `nil` value in the error position indicates that
|
||||
// there was no error.
|
||||
return arg + 3, nil
|
||||
}
|
||||
|
||||
// It's possible to use custom types as `error`s by
|
||||
@ -33,53 +33,53 @@ func f1(arg int) (int, error) {
|
||||
// variant on the example above that uses a custom type
|
||||
// to explicitly represent an argument error.
|
||||
type argError struct {
|
||||
arg int
|
||||
prob string
|
||||
arg int
|
||||
prob string
|
||||
}
|
||||
|
||||
func (e *argError) Error() string {
|
||||
return fmt.Sprintf("%d - %s", e.arg, e.prob)
|
||||
return fmt.Sprintf("%d - %s", e.arg, e.prob)
|
||||
}
|
||||
|
||||
func f2(arg int) (int, error) {
|
||||
if arg == 42 {
|
||||
if arg == 42 {
|
||||
|
||||
// In this case we use `&argError` syntax to build
|
||||
// a new struct, supplying values for the two
|
||||
// fields `arg` and `prob`.
|
||||
return -1, &argError{arg, "can't work with it"}
|
||||
}
|
||||
return arg + 3, nil
|
||||
// In this case we use `&argError` syntax to build
|
||||
// a new struct, supplying values for the two
|
||||
// fields `arg` and `prob`.
|
||||
return -1, &argError{arg, "can't work with it"}
|
||||
}
|
||||
return arg + 3, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// The two loops below test out each of our
|
||||
// error-returning functions. Note that the use of an
|
||||
// inline error check on the `if` line is a common
|
||||
// idiom in Go code.
|
||||
for _, i := range []int{7, 42} {
|
||||
if r, e := f1(i); e != nil {
|
||||
fmt.Println("f1 failed:", e)
|
||||
} else {
|
||||
fmt.Println("f1 worked:", r)
|
||||
}
|
||||
}
|
||||
for _, i := range []int{7, 42} {
|
||||
if r, e := f2(i); e != nil {
|
||||
fmt.Println("f2 failed:", e)
|
||||
} else {
|
||||
fmt.Println("f2 worked:", r)
|
||||
}
|
||||
}
|
||||
// The two loops below test out each of our
|
||||
// error-returning functions. Note that the use of an
|
||||
// inline error check on the `if` line is a common
|
||||
// idiom in Go code.
|
||||
for _, i := range []int{7, 42} {
|
||||
if r, e := f1(i); e != nil {
|
||||
fmt.Println("f1 failed:", e)
|
||||
} else {
|
||||
fmt.Println("f1 worked:", r)
|
||||
}
|
||||
}
|
||||
for _, i := range []int{7, 42} {
|
||||
if r, e := f2(i); e != nil {
|
||||
fmt.Println("f2 failed:", e)
|
||||
} else {
|
||||
fmt.Println("f2 worked:", r)
|
||||
}
|
||||
}
|
||||
|
||||
// If you want to programmatically use the data in
|
||||
// a custom error, you'll need to get the error as an
|
||||
// instance of the custom error type via type
|
||||
// assertion.
|
||||
_, e := f2(42)
|
||||
if ae, ok := e.(*argError); ok {
|
||||
fmt.Println(ae.arg)
|
||||
fmt.Println(ae.prob)
|
||||
}
|
||||
// If you want to programmatically use the data in
|
||||
// a custom error, you'll need to get the error as an
|
||||
// instance of the custom error type via type
|
||||
// assertion.
|
||||
_, e := f2(42)
|
||||
if ae, ok := e.(*argError); ok {
|
||||
fmt.Println(ae.arg)
|
||||
fmt.Println(ae.prob)
|
||||
}
|
||||
}
|
||||
|
@ -16,33 +16,33 @@ import "os/exec"
|
||||
|
||||
func main() {
|
||||
|
||||
// For our example we'll exec `ls`. Go requires an
|
||||
// absolute path to the binary we want to execute, so
|
||||
// we'll use `exec.LookPath` to find it (probably
|
||||
// `/bin/ls`).
|
||||
binary, lookErr := exec.LookPath("ls")
|
||||
if lookErr != nil {
|
||||
panic(lookErr)
|
||||
}
|
||||
// For our example we'll exec `ls`. Go requires an
|
||||
// absolute path to the binary we want to execute, so
|
||||
// we'll use `exec.LookPath` to find it (probably
|
||||
// `/bin/ls`).
|
||||
binary, lookErr := exec.LookPath("ls")
|
||||
if lookErr != nil {
|
||||
panic(lookErr)
|
||||
}
|
||||
|
||||
// `Exec` requires arguments in slice form (as
|
||||
// apposed to one big string). We'll give `ls` a few
|
||||
// common arguments. Note that the first argument should
|
||||
// be the program name.
|
||||
args := []string{"ls", "-a", "-l", "-h"}
|
||||
// `Exec` requires arguments in slice form (as
|
||||
// apposed to one big string). We'll give `ls` a few
|
||||
// common arguments. Note that the first argument should
|
||||
// be the program name.
|
||||
args := []string{"ls", "-a", "-l", "-h"}
|
||||
|
||||
// `Exec` also needs a set of [environment variables](environment-variables)
|
||||
// to use. Here we just provide our current
|
||||
// environment.
|
||||
env := os.Environ()
|
||||
// `Exec` also needs a set of [environment variables](environment-variables)
|
||||
// to use. Here we just provide our current
|
||||
// environment.
|
||||
env := os.Environ()
|
||||
|
||||
// Here's the actual `syscall.Exec` call. If this call is
|
||||
// successful, the execution of our process will end
|
||||
// here and be replaced by the `/bin/ls -a -l -h`
|
||||
// process. If there is an error we'll get a return
|
||||
// value.
|
||||
execErr := syscall.Exec(binary, args, env)
|
||||
if execErr != nil {
|
||||
panic(execErr)
|
||||
}
|
||||
// Here's the actual `syscall.Exec` call. If this call is
|
||||
// successful, the execution of our process will end
|
||||
// here and be replaced by the `/bin/ls -a -l -h`
|
||||
// process. If there is an error we'll get a return
|
||||
// value.
|
||||
execErr := syscall.Exec(binary, args, env)
|
||||
if execErr != nil {
|
||||
panic(execErr)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
b527bbb76a42dd4bae541b73a7377b7e83e79905
|
||||
neqdJ51KLN
|
||||
bf11ADw-2Ho
|
||||
|
@ -8,12 +8,12 @@ import "os"
|
||||
|
||||
func main() {
|
||||
|
||||
// `defer`s will _not_ be run when using `os.Exit`, so
|
||||
// this `fmt.Println` will never be called.
|
||||
defer fmt.Println("!")
|
||||
// `defer`s will _not_ be run when using `os.Exit`, so
|
||||
// this `fmt.Println` will never be called.
|
||||
defer fmt.Println("!")
|
||||
|
||||
// Exit with status 3.
|
||||
os.Exit(3)
|
||||
// Exit with status 3.
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
// Note that unlike e.g. C, Go does not use an integer
|
||||
|
@ -1,2 +1,2 @@
|
||||
dc0bb3eaafa045d6aa05e88aff39322a1ccf822e
|
||||
CDiAh9SXRM
|
||||
vDaM0-MGJ_k
|
||||
|
@ -7,32 +7,32 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// The most basic type, with a single condition.
|
||||
i := 1
|
||||
for i <= 3 {
|
||||
fmt.Println(i)
|
||||
i = i + 1
|
||||
}
|
||||
// The most basic type, with a single condition.
|
||||
i := 1
|
||||
for i <= 3 {
|
||||
fmt.Println(i)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
// A classic initial/condition/after `for` loop.
|
||||
for j := 7; j <= 9; j++ {
|
||||
fmt.Println(j)
|
||||
}
|
||||
// A classic initial/condition/after `for` loop.
|
||||
for j := 7; j <= 9; j++ {
|
||||
fmt.Println(j)
|
||||
}
|
||||
|
||||
// `for` without a condition will loop repeatedly
|
||||
// until you `break` out of the loop or `return` from
|
||||
// the enclosing function.
|
||||
for {
|
||||
fmt.Println("loop")
|
||||
break
|
||||
}
|
||||
// `for` without a condition will loop repeatedly
|
||||
// until you `break` out of the loop or `return` from
|
||||
// the enclosing function.
|
||||
for {
|
||||
fmt.Println("loop")
|
||||
break
|
||||
}
|
||||
|
||||
// You can also `continue` to the next iteration of
|
||||
// the loop.
|
||||
for n := 0; n <= 5; n++ {
|
||||
if n%2 == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Println(n)
|
||||
}
|
||||
// You can also `continue` to the next iteration of
|
||||
// the loop.
|
||||
for n := 0; n <= 5; n++ {
|
||||
if n%2 == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Println(n)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
33056d6b36f9894fb6359c9cf2ef8725bbdafa19
|
||||
KNLLSX4Io_
|
||||
lGYfUJwiGfi
|
||||
|
@ -9,10 +9,10 @@ import "fmt"
|
||||
// their sum as an `int`.
|
||||
func plus(a int, b int) int {
|
||||
|
||||
// Go requires explicit returns, i.e. it won't
|
||||
// automatically return the value of the last
|
||||
// expression.
|
||||
return a + b
|
||||
// Go requires explicit returns, i.e. it won't
|
||||
// automatically return the value of the last
|
||||
// expression.
|
||||
return a + b
|
||||
}
|
||||
|
||||
// When you have multiple consecutive parameters of
|
||||
@ -20,16 +20,16 @@ func plus(a int, b int) int {
|
||||
// like-typed parameters up to the final parameter that
|
||||
// declares the type.
|
||||
func plusPlus(a, b, c int) int {
|
||||
return a + b + c
|
||||
return a + b + c
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Call a function just as you'd expect, with
|
||||
// `name(args)`.
|
||||
res := plus(1, 2)
|
||||
fmt.Println("1+2 =", res)
|
||||
// Call a function just as you'd expect, with
|
||||
// `name(args)`.
|
||||
res := plus(1, 2)
|
||||
fmt.Println("1+2 =", res)
|
||||
|
||||
res = plusPlus(1, 2, 3)
|
||||
fmt.Println("1+2+3 =", res)
|
||||
res = plusPlus(1, 2, 3)
|
||||
fmt.Println("1+2+3 =", res)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
ae669923c20e5ebf4a7b4b11b8fdf2972accf9e2
|
||||
9Nky-Dn49f
|
||||
hzGUvK6iJNm
|
||||
|
@ -5,33 +5,33 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func f(from string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
fmt.Println(from, ":", i)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
fmt.Println(from, ":", i)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Suppose we have a function call `f(s)`. Here's how
|
||||
// we'd call that in the usual way, running it
|
||||
// synchronously.
|
||||
f("direct")
|
||||
// Suppose we have a function call `f(s)`. Here's how
|
||||
// we'd call that in the usual way, running it
|
||||
// synchronously.
|
||||
f("direct")
|
||||
|
||||
// To invoke this function in a goroutine, use
|
||||
// `go f(s)`. This new goroutine will execute
|
||||
// concurrently with the calling one.
|
||||
go f("goroutine")
|
||||
// To invoke this function in a goroutine, use
|
||||
// `go f(s)`. This new goroutine will execute
|
||||
// concurrently with the calling one.
|
||||
go f("goroutine")
|
||||
|
||||
// You can also start a goroutine for an anonymous
|
||||
// function call.
|
||||
go func(msg string) {
|
||||
fmt.Println(msg)
|
||||
}("going")
|
||||
// You can also start a goroutine for an anonymous
|
||||
// function call.
|
||||
go func(msg string) {
|
||||
fmt.Println(msg)
|
||||
}("going")
|
||||
|
||||
// Our two function calls are running asynchronously in
|
||||
// separate goroutines now, so execution falls through
|
||||
// to here. This `Scanln` requires we press a key
|
||||
// before the program exits.
|
||||
fmt.Scanln()
|
||||
fmt.Println("done")
|
||||
// Our two function calls are running asynchronously in
|
||||
// separate goroutines now, so execution falls through
|
||||
// to here. This `Scanln` requires we press a key
|
||||
// before the program exits.
|
||||
fmt.Scanln()
|
||||
fmt.Println("done")
|
||||
}
|
||||
|
@ -5,5 +5,5 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello world")
|
||||
fmt.Println("hello world")
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
c98395a44701add5bf84e2f3a63e300fc1bc4bfe
|
||||
2C7wwJ6nxG
|
||||
mp1ENMU6ZYu
|
||||
|
@ -5,34 +5,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Issue an HTTP GET request to a server. `http.Get` is a
|
||||
// convenient shortcut around creating an `http.Client`
|
||||
// object and calling its `Get` method; it uses the
|
||||
// `http.DefaultClient` object which has useful default
|
||||
// settings.
|
||||
resp, err := http.Get("http://gobyexample.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// Issue an HTTP GET request to a server. `http.Get` is a
|
||||
// convenient shortcut around creating an `http.Client`
|
||||
// object and calling its `Get` method; it uses the
|
||||
// `http.DefaultClient` object which has useful default
|
||||
// settings.
|
||||
resp, err := http.Get("http://gobyexample.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Print the HTTP response status.
|
||||
fmt.Println("Response status:", resp.Status)
|
||||
// Print the HTTP response status.
|
||||
fmt.Println("Response status:", resp.Status)
|
||||
|
||||
// Print the first 5 lines of the response body.
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for i := 0; scanner.Scan() && i < 5; i++ {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
// Print the first 5 lines of the response body.
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
for i := 0; scanner.Scan() && i < 5; i++ {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -7,28 +7,28 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here's a basic example.
|
||||
if 7%2 == 0 {
|
||||
fmt.Println("7 is even")
|
||||
} else {
|
||||
fmt.Println("7 is odd")
|
||||
}
|
||||
// Here's a basic example.
|
||||
if 7%2 == 0 {
|
||||
fmt.Println("7 is even")
|
||||
} else {
|
||||
fmt.Println("7 is odd")
|
||||
}
|
||||
|
||||
// You can have an `if` statement without an else.
|
||||
if 8%4 == 0 {
|
||||
fmt.Println("8 is divisible by 4")
|
||||
}
|
||||
// You can have an `if` statement without an else.
|
||||
if 8%4 == 0 {
|
||||
fmt.Println("8 is divisible by 4")
|
||||
}
|
||||
|
||||
// A statement can precede conditionals; any variables
|
||||
// declared in this statement are available in all
|
||||
// branches.
|
||||
if num := 9; num < 0 {
|
||||
fmt.Println(num, "is negative")
|
||||
} else if num < 10 {
|
||||
fmt.Println(num, "has 1 digit")
|
||||
} else {
|
||||
fmt.Println(num, "has multiple digits")
|
||||
}
|
||||
// A statement can precede conditionals; any variables
|
||||
// declared in this statement are available in all
|
||||
// branches.
|
||||
if num := 9; num < 0 {
|
||||
fmt.Println(num, "is negative")
|
||||
} else if num < 10 {
|
||||
fmt.Println(num, "has 1 digit")
|
||||
} else {
|
||||
fmt.Println(num, "has multiple digits")
|
||||
}
|
||||
}
|
||||
|
||||
// Note that you don't need parentheses around conditions
|
||||
|
@ -1,2 +1,2 @@
|
||||
89b78f3378e1a574ddfd0260a0404a962852eff8
|
||||
g-aqMz0Ivf
|
||||
p6-WKTqEks4
|
||||
|
@ -8,35 +8,35 @@ import "math"
|
||||
|
||||
// Here's a basic interface for geometric shapes.
|
||||
type geometry interface {
|
||||
area() float64
|
||||
perim() float64
|
||||
area() float64
|
||||
perim() float64
|
||||
}
|
||||
|
||||
// For our example we'll implement this interface on
|
||||
// `rect` and `circle` types.
|
||||
type rect struct {
|
||||
width, height float64
|
||||
width, height float64
|
||||
}
|
||||
type circle struct {
|
||||
radius float64
|
||||
radius float64
|
||||
}
|
||||
|
||||
// To implement an interface in Go, we just need to
|
||||
// implement all the methods in the interface. Here we
|
||||
// implement `geometry` on `rect`s.
|
||||
func (r rect) area() float64 {
|
||||
return r.width * r.height
|
||||
return r.width * r.height
|
||||
}
|
||||
func (r rect) perim() float64 {
|
||||
return 2*r.width + 2*r.height
|
||||
return 2*r.width + 2*r.height
|
||||
}
|
||||
|
||||
// The implementation for `circle`s.
|
||||
func (c circle) area() float64 {
|
||||
return math.Pi * c.radius * c.radius
|
||||
return math.Pi * c.radius * c.radius
|
||||
}
|
||||
func (c circle) perim() float64 {
|
||||
return 2 * math.Pi * c.radius
|
||||
return 2 * math.Pi * c.radius
|
||||
}
|
||||
|
||||
// If a variable has an interface type, then we can call
|
||||
@ -44,19 +44,19 @@ func (c circle) perim() float64 {
|
||||
// generic `measure` function taking advantage of this
|
||||
// to work on any `geometry`.
|
||||
func measure(g geometry) {
|
||||
fmt.Println(g)
|
||||
fmt.Println(g.area())
|
||||
fmt.Println(g.perim())
|
||||
fmt.Println(g)
|
||||
fmt.Println(g.area())
|
||||
fmt.Println(g.perim())
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := rect{width: 3, height: 4}
|
||||
c := circle{radius: 5}
|
||||
r := rect{width: 3, height: 4}
|
||||
c := circle{radius: 5}
|
||||
|
||||
// The `circle` and `rect` struct types both
|
||||
// implement the `geometry` interface so we can use
|
||||
// instances of
|
||||
// these structs as arguments to `measure`.
|
||||
measure(r)
|
||||
measure(c)
|
||||
// The `circle` and `rect` struct types both
|
||||
// implement the `geometry` interface so we can use
|
||||
// instances of
|
||||
// these structs as arguments to `measure`.
|
||||
measure(r)
|
||||
measure(c)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
3547b935d1e0322c0fb696726c27cae53a275e0a
|
||||
313UebA3rD
|
||||
0EwsqIn3TTi
|
||||
|
@ -11,109 +11,109 @@ import "os"
|
||||
// We'll use these two structs to demonstrate encoding and
|
||||
// decoding of custom types below.
|
||||
type response1 struct {
|
||||
Page int
|
||||
Fruits []string
|
||||
Page int
|
||||
Fruits []string
|
||||
}
|
||||
type response2 struct {
|
||||
Page int `json:"page"`
|
||||
Fruits []string `json:"fruits"`
|
||||
Page int `json:"page"`
|
||||
Fruits []string `json:"fruits"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// First we'll look at encoding basic data types to
|
||||
// JSON strings. Here are some examples for atomic
|
||||
// values.
|
||||
bolB, _ := json.Marshal(true)
|
||||
fmt.Println(string(bolB))
|
||||
// First we'll look at encoding basic data types to
|
||||
// JSON strings. Here are some examples for atomic
|
||||
// values.
|
||||
bolB, _ := json.Marshal(true)
|
||||
fmt.Println(string(bolB))
|
||||
|
||||
intB, _ := json.Marshal(1)
|
||||
fmt.Println(string(intB))
|
||||
intB, _ := json.Marshal(1)
|
||||
fmt.Println(string(intB))
|
||||
|
||||
fltB, _ := json.Marshal(2.34)
|
||||
fmt.Println(string(fltB))
|
||||
fltB, _ := json.Marshal(2.34)
|
||||
fmt.Println(string(fltB))
|
||||
|
||||
strB, _ := json.Marshal("gopher")
|
||||
fmt.Println(string(strB))
|
||||
strB, _ := json.Marshal("gopher")
|
||||
fmt.Println(string(strB))
|
||||
|
||||
// And here are some for slices and maps, which encode
|
||||
// to JSON arrays and objects as you'd expect.
|
||||
slcD := []string{"apple", "peach", "pear"}
|
||||
slcB, _ := json.Marshal(slcD)
|
||||
fmt.Println(string(slcB))
|
||||
// And here are some for slices and maps, which encode
|
||||
// to JSON arrays and objects as you'd expect.
|
||||
slcD := []string{"apple", "peach", "pear"}
|
||||
slcB, _ := json.Marshal(slcD)
|
||||
fmt.Println(string(slcB))
|
||||
|
||||
mapD := map[string]int{"apple": 5, "lettuce": 7}
|
||||
mapB, _ := json.Marshal(mapD)
|
||||
fmt.Println(string(mapB))
|
||||
mapD := map[string]int{"apple": 5, "lettuce": 7}
|
||||
mapB, _ := json.Marshal(mapD)
|
||||
fmt.Println(string(mapB))
|
||||
|
||||
// The JSON package can automatically encode your
|
||||
// custom data types. It will only include exported
|
||||
// fields in the encoded output and will by default
|
||||
// use those names as the JSON keys.
|
||||
res1D := &response1{
|
||||
Page: 1,
|
||||
Fruits: []string{"apple", "peach", "pear"}}
|
||||
res1B, _ := json.Marshal(res1D)
|
||||
fmt.Println(string(res1B))
|
||||
// The JSON package can automatically encode your
|
||||
// custom data types. It will only include exported
|
||||
// fields in the encoded output and will by default
|
||||
// use those names as the JSON keys.
|
||||
res1D := &response1{
|
||||
Page: 1,
|
||||
Fruits: []string{"apple", "peach", "pear"}}
|
||||
res1B, _ := json.Marshal(res1D)
|
||||
fmt.Println(string(res1B))
|
||||
|
||||
// You can use tags on struct field declarations
|
||||
// to customize the encoded JSON key names. Check the
|
||||
// definition of `response2` above to see an example
|
||||
// of such tags.
|
||||
res2D := &response2{
|
||||
Page: 1,
|
||||
Fruits: []string{"apple", "peach", "pear"}}
|
||||
res2B, _ := json.Marshal(res2D)
|
||||
fmt.Println(string(res2B))
|
||||
// You can use tags on struct field declarations
|
||||
// to customize the encoded JSON key names. Check the
|
||||
// definition of `response2` above to see an example
|
||||
// of such tags.
|
||||
res2D := &response2{
|
||||
Page: 1,
|
||||
Fruits: []string{"apple", "peach", "pear"}}
|
||||
res2B, _ := json.Marshal(res2D)
|
||||
fmt.Println(string(res2B))
|
||||
|
||||
// Now let's look at decoding JSON data into Go
|
||||
// values. Here's an example for a generic data
|
||||
// structure.
|
||||
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
|
||||
// Now let's look at decoding JSON data into Go
|
||||
// values. Here's an example for a generic data
|
||||
// structure.
|
||||
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
|
||||
|
||||
// We need to provide a variable where the JSON
|
||||
// package can put the decoded data. This
|
||||
// `map[string]interface{}` will hold a map of strings
|
||||
// to arbitrary data types.
|
||||
var dat map[string]interface{}
|
||||
// We need to provide a variable where the JSON
|
||||
// package can put the decoded data. This
|
||||
// `map[string]interface{}` will hold a map of strings
|
||||
// to arbitrary data types.
|
||||
var dat map[string]interface{}
|
||||
|
||||
// Here's the actual decoding, and a check for
|
||||
// associated errors.
|
||||
if err := json.Unmarshal(byt, &dat); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(dat)
|
||||
// Here's the actual decoding, and a check for
|
||||
// associated errors.
|
||||
if err := json.Unmarshal(byt, &dat); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(dat)
|
||||
|
||||
// In order to use the values in the decoded map,
|
||||
// we'll need to convert them to their appropriate type.
|
||||
// For example here we convert the value in `num` to
|
||||
// the expected `float64` type.
|
||||
num := dat["num"].(float64)
|
||||
fmt.Println(num)
|
||||
// In order to use the values in the decoded map,
|
||||
// we'll need to convert them to their appropriate type.
|
||||
// For example here we convert the value in `num` to
|
||||
// the expected `float64` type.
|
||||
num := dat["num"].(float64)
|
||||
fmt.Println(num)
|
||||
|
||||
// Accessing nested data requires a series of
|
||||
// conversions.
|
||||
strs := dat["strs"].([]interface{})
|
||||
str1 := strs[0].(string)
|
||||
fmt.Println(str1)
|
||||
// Accessing nested data requires a series of
|
||||
// conversions.
|
||||
strs := dat["strs"].([]interface{})
|
||||
str1 := strs[0].(string)
|
||||
fmt.Println(str1)
|
||||
|
||||
// We can also decode JSON into custom data types.
|
||||
// This has the advantages of adding additional
|
||||
// type-safety to our programs and eliminating the
|
||||
// need for type assertions when accessing the decoded
|
||||
// data.
|
||||
str := `{"page": 1, "fruits": ["apple", "peach"]}`
|
||||
res := response2{}
|
||||
json.Unmarshal([]byte(str), &res)
|
||||
fmt.Println(res)
|
||||
fmt.Println(res.Fruits[0])
|
||||
// We can also decode JSON into custom data types.
|
||||
// This has the advantages of adding additional
|
||||
// type-safety to our programs and eliminating the
|
||||
// need for type assertions when accessing the decoded
|
||||
// data.
|
||||
str := `{"page": 1, "fruits": ["apple", "peach"]}`
|
||||
res := response2{}
|
||||
json.Unmarshal([]byte(str), &res)
|
||||
fmt.Println(res)
|
||||
fmt.Println(res.Fruits[0])
|
||||
|
||||
// In the examples above we always used bytes and
|
||||
// strings as intermediates between the data and
|
||||
// JSON representation on standard out. We can also
|
||||
// stream JSON encodings directly to `os.Writer`s like
|
||||
// `os.Stdout` or even HTTP response bodies.
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
d := map[string]int{"apple": 5, "lettuce": 7}
|
||||
enc.Encode(d)
|
||||
// In the examples above we always used bytes and
|
||||
// strings as intermediates between the data and
|
||||
// JSON representation on standard out. We can also
|
||||
// stream JSON encodings directly to `os.Writer`s like
|
||||
// `os.Stdout` or even HTTP response bodies.
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
d := map[string]int{"apple": 5, "lettuce": 7}
|
||||
enc.Encode(d)
|
||||
}
|
||||
|
@ -9,33 +9,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Wrapping the unbuffered `os.Stdin` with a buffered
|
||||
// scanner gives us a convenient `Scan` method that
|
||||
// advances the scanner to the next token; which is
|
||||
// the next line in the default scanner.
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
// Wrapping the unbuffered `os.Stdin` with a buffered
|
||||
// scanner gives us a convenient `Scan` method that
|
||||
// advances the scanner to the next token; which is
|
||||
// the next line in the default scanner.
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
for scanner.Scan() {
|
||||
// `Text` returns the current token, here the next line,
|
||||
// from the input.
|
||||
ucl := strings.ToUpper(scanner.Text())
|
||||
for scanner.Scan() {
|
||||
// `Text` returns the current token, here the next line,
|
||||
// from the input.
|
||||
ucl := strings.ToUpper(scanner.Text())
|
||||
|
||||
// Write out the uppercased line.
|
||||
fmt.Println(ucl)
|
||||
}
|
||||
// Write out the uppercased line.
|
||||
fmt.Println(ucl)
|
||||
}
|
||||
|
||||
// Check for errors during `Scan`. End of file is
|
||||
// expected and not reported by `Scan` as an error.
|
||||
if err := scanner.Err(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// Check for errors during `Scan`. End of file is
|
||||
// expected and not reported by `Scan` as an error.
|
||||
if err := scanner.Err(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "error:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
87f4a67edf741979f8ff6da85947aa177547f9ef
|
||||
mpYwOHj2ma
|
||||
hnaOIaQAjKF
|
||||
|
@ -7,44 +7,44 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// To create an empty map, use the builtin `make`:
|
||||
// `make(map[key-type]val-type)`.
|
||||
m := make(map[string]int)
|
||||
// To create an empty map, use the builtin `make`:
|
||||
// `make(map[key-type]val-type)`.
|
||||
m := make(map[string]int)
|
||||
|
||||
// Set key/value pairs using typical `name[key] = val`
|
||||
// syntax.
|
||||
m["k1"] = 7
|
||||
m["k2"] = 13
|
||||
// Set key/value pairs using typical `name[key] = val`
|
||||
// syntax.
|
||||
m["k1"] = 7
|
||||
m["k2"] = 13
|
||||
|
||||
// Printing a map with e.g. `fmt.Println` will show all of
|
||||
// its key/value pairs.
|
||||
fmt.Println("map:", m)
|
||||
// Printing a map with e.g. `fmt.Println` will show all of
|
||||
// its key/value pairs.
|
||||
fmt.Println("map:", m)
|
||||
|
||||
// Get a value for a key with `name[key]`.
|
||||
v1 := m["k1"]
|
||||
fmt.Println("v1: ", v1)
|
||||
// Get a value for a key with `name[key]`.
|
||||
v1 := m["k1"]
|
||||
fmt.Println("v1: ", v1)
|
||||
|
||||
// The builtin `len` returns the number of key/value
|
||||
// pairs when called on a map.
|
||||
fmt.Println("len:", len(m))
|
||||
// The builtin `len` returns the number of key/value
|
||||
// pairs when called on a map.
|
||||
fmt.Println("len:", len(m))
|
||||
|
||||
// The builtin `delete` removes key/value pairs from
|
||||
// a map.
|
||||
delete(m, "k2")
|
||||
fmt.Println("map:", m)
|
||||
// The builtin `delete` removes key/value pairs from
|
||||
// a map.
|
||||
delete(m, "k2")
|
||||
fmt.Println("map:", m)
|
||||
|
||||
// The optional second return value when getting a
|
||||
// value from a map indicates if the key was present
|
||||
// in the map. This can be used to disambiguate
|
||||
// between missing keys and keys with zero values
|
||||
// like `0` or `""`. Here we didn't need the value
|
||||
// itself, so we ignored it with the _blank identifier_
|
||||
// `_`.
|
||||
_, prs := m["k2"]
|
||||
fmt.Println("prs:", prs)
|
||||
// The optional second return value when getting a
|
||||
// value from a map indicates if the key was present
|
||||
// in the map. This can be used to disambiguate
|
||||
// between missing keys and keys with zero values
|
||||
// like `0` or `""`. Here we didn't need the value
|
||||
// itself, so we ignored it with the _blank identifier_
|
||||
// `_`.
|
||||
_, prs := m["k2"]
|
||||
fmt.Println("prs:", prs)
|
||||
|
||||
// You can also declare and initialize a new map in
|
||||
// the same line with this syntax.
|
||||
n := map[string]int{"foo": 1, "bar": 2}
|
||||
fmt.Println("map:", n)
|
||||
// You can also declare and initialize a new map in
|
||||
// the same line with this syntax.
|
||||
n := map[string]int{"foo": 1, "bar": 2}
|
||||
fmt.Println("map:", n)
|
||||
}
|
||||
|
@ -5,33 +5,33 @@ package main
|
||||
import "fmt"
|
||||
|
||||
type rect struct {
|
||||
width, height int
|
||||
width, height int
|
||||
}
|
||||
|
||||
// This `area` method has a _receiver type_ of `*rect`.
|
||||
func (r *rect) area() int {
|
||||
return r.width * r.height
|
||||
return r.width * r.height
|
||||
}
|
||||
|
||||
// Methods can be defined for either pointer or value
|
||||
// receiver types. Here's an example of a value receiver.
|
||||
func (r rect) perim() int {
|
||||
return 2*r.width + 2*r.height
|
||||
return 2*r.width + 2*r.height
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := rect{width: 10, height: 5}
|
||||
r := rect{width: 10, height: 5}
|
||||
|
||||
// Here we call the 2 methods defined for our struct.
|
||||
fmt.Println("area: ", r.area())
|
||||
fmt.Println("perim:", r.perim())
|
||||
// Here we call the 2 methods defined for our struct.
|
||||
fmt.Println("area: ", r.area())
|
||||
fmt.Println("perim:", r.perim())
|
||||
|
||||
// Go automatically handles conversion between values
|
||||
// and pointers for method calls. You may want to use
|
||||
// a pointer receiver type to avoid copying on method
|
||||
// calls or to allow the method to mutate the
|
||||
// receiving struct.
|
||||
rp := &r
|
||||
fmt.Println("area: ", rp.area())
|
||||
fmt.Println("perim:", rp.perim())
|
||||
// Go automatically handles conversion between values
|
||||
// and pointers for method calls. You may want to use
|
||||
// a pointer receiver type to avoid copying on method
|
||||
// calls or to allow the method to mutate the
|
||||
// receiving struct.
|
||||
rp := &r
|
||||
fmt.Println("area: ", rp.area())
|
||||
fmt.Println("perim:", rp.perim())
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
24cfb9ad45e43c2d49163149bc55925a4e1b3c7a
|
||||
254m_9Yjwa
|
||||
ffMb0txGnYB
|
||||
|
@ -9,19 +9,19 @@ import "fmt"
|
||||
// The `(int, int)` in this function signature shows that
|
||||
// the function returns 2 `int`s.
|
||||
func vals() (int, int) {
|
||||
return 3, 7
|
||||
return 3, 7
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Here we use the 2 different return values from the
|
||||
// call with _multiple assignment_.
|
||||
a, b := vals()
|
||||
fmt.Println(a)
|
||||
fmt.Println(b)
|
||||
// Here we use the 2 different return values from the
|
||||
// call with _multiple assignment_.
|
||||
a, b := vals()
|
||||
fmt.Println(a)
|
||||
fmt.Println(b)
|
||||
|
||||
// If you only want a subset of the returned values,
|
||||
// use the blank identifier `_`.
|
||||
_, c := vals()
|
||||
fmt.Println(c)
|
||||
// If you only want a subset of the returned values,
|
||||
// use the blank identifier `_`.
|
||||
_, c := vals()
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
5063ce3d3c70c6bd70f4b709de24bb93d0f24e0c
|
||||
chwFmr5dG1
|
||||
FZoIB5LXQGZ
|
||||
|
@ -6,80 +6,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// For our example the `state` will be a map.
|
||||
var state = make(map[int]int)
|
||||
// For our example the `state` will be a map.
|
||||
var state = make(map[int]int)
|
||||
|
||||
// This `mutex` will synchronize access to `state`.
|
||||
var mutex = &sync.Mutex{}
|
||||
// This `mutex` will synchronize access to `state`.
|
||||
var mutex = &sync.Mutex{}
|
||||
|
||||
// We'll keep track of how many read and write
|
||||
// operations we do.
|
||||
var readOps uint64
|
||||
var writeOps uint64
|
||||
// We'll keep track of how many read and write
|
||||
// operations we do.
|
||||
var readOps uint64
|
||||
var writeOps uint64
|
||||
|
||||
// Here we start 100 goroutines to execute repeated
|
||||
// reads against the state, once per millisecond in
|
||||
// each goroutine.
|
||||
for r := 0; r < 100; r++ {
|
||||
go func() {
|
||||
total := 0
|
||||
for {
|
||||
// Here we start 100 goroutines to execute repeated
|
||||
// reads against the state, once per millisecond in
|
||||
// each goroutine.
|
||||
for r := 0; r < 100; r++ {
|
||||
go func() {
|
||||
total := 0
|
||||
for {
|
||||
|
||||
// For each read we pick a key to access,
|
||||
// `Lock()` the `mutex` to ensure
|
||||
// exclusive access to the `state`, read
|
||||
// the value at the chosen key,
|
||||
// `Unlock()` the mutex, and increment
|
||||
// the `readOps` count.
|
||||
key := rand.Intn(5)
|
||||
mutex.Lock()
|
||||
total += state[key]
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&readOps, 1)
|
||||
// For each read we pick a key to access,
|
||||
// `Lock()` the `mutex` to ensure
|
||||
// exclusive access to the `state`, read
|
||||
// the value at the chosen key,
|
||||
// `Unlock()` the mutex, and increment
|
||||
// the `readOps` count.
|
||||
key := rand.Intn(5)
|
||||
mutex.Lock()
|
||||
total += state[key]
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&readOps, 1)
|
||||
|
||||
// Wait a bit between reads.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Wait a bit between reads.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// We'll also start 10 goroutines to simulate writes,
|
||||
// using the same pattern we did for reads.
|
||||
for w := 0; w < 10; w++ {
|
||||
go func() {
|
||||
for {
|
||||
key := rand.Intn(5)
|
||||
val := rand.Intn(100)
|
||||
mutex.Lock()
|
||||
state[key] = val
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&writeOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// We'll also start 10 goroutines to simulate writes,
|
||||
// using the same pattern we did for reads.
|
||||
for w := 0; w < 10; w++ {
|
||||
go func() {
|
||||
for {
|
||||
key := rand.Intn(5)
|
||||
val := rand.Intn(100)
|
||||
mutex.Lock()
|
||||
state[key] = val
|
||||
mutex.Unlock()
|
||||
atomic.AddUint64(&writeOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Let the 10 goroutines work on the `state` and
|
||||
// `mutex` for a second.
|
||||
time.Sleep(time.Second)
|
||||
// Let the 10 goroutines work on the `state` and
|
||||
// `mutex` for a second.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// Take and report final operation counts.
|
||||
readOpsFinal := atomic.LoadUint64(&readOps)
|
||||
fmt.Println("readOps:", readOpsFinal)
|
||||
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
||||
fmt.Println("writeOps:", writeOpsFinal)
|
||||
// Take and report final operation counts.
|
||||
readOpsFinal := atomic.LoadUint64(&readOps)
|
||||
fmt.Println("readOps:", readOpsFinal)
|
||||
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
||||
fmt.Println("writeOps:", writeOpsFinal)
|
||||
|
||||
// With a final lock of `state`, show how it ended up.
|
||||
mutex.Lock()
|
||||
fmt.Println("state:", state)
|
||||
mutex.Unlock()
|
||||
// With a final lock of `state`, show how it ended up.
|
||||
mutex.Lock()
|
||||
fmt.Println("state:", state)
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
@ -8,42 +8,42 @@ package main
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
messages := make(chan string)
|
||||
signals := make(chan bool)
|
||||
messages := make(chan string)
|
||||
signals := make(chan bool)
|
||||
|
||||
// Here's a non-blocking receive. If a value is
|
||||
// available on `messages` then `select` will take
|
||||
// the `<-messages` `case` with that value. If not
|
||||
// it will immediately take the `default` case.
|
||||
select {
|
||||
case msg := <-messages:
|
||||
fmt.Println("received message", msg)
|
||||
default:
|
||||
fmt.Println("no message received")
|
||||
}
|
||||
// Here's a non-blocking receive. If a value is
|
||||
// available on `messages` then `select` will take
|
||||
// the `<-messages` `case` with that value. If not
|
||||
// it will immediately take the `default` case.
|
||||
select {
|
||||
case msg := <-messages:
|
||||
fmt.Println("received message", msg)
|
||||
default:
|
||||
fmt.Println("no message received")
|
||||
}
|
||||
|
||||
// A non-blocking send works similarly. Here `msg`
|
||||
// cannot be sent to the `messages` channel, because
|
||||
// the channel has no buffer and there is no receiver.
|
||||
// Therefore the `default` case is selected.
|
||||
msg := "hi"
|
||||
select {
|
||||
case messages <- msg:
|
||||
fmt.Println("sent message", msg)
|
||||
default:
|
||||
fmt.Println("no message sent")
|
||||
}
|
||||
// A non-blocking send works similarly. Here `msg`
|
||||
// cannot be sent to the `messages` channel, because
|
||||
// the channel has no buffer and there is no receiver.
|
||||
// Therefore the `default` case is selected.
|
||||
msg := "hi"
|
||||
select {
|
||||
case messages <- msg:
|
||||
fmt.Println("sent message", msg)
|
||||
default:
|
||||
fmt.Println("no message sent")
|
||||
}
|
||||
|
||||
// We can use multiple `case`s above the `default`
|
||||
// clause to implement a multi-way non-blocking
|
||||
// select. Here we attempt non-blocking receives
|
||||
// on both `messages` and `signals`.
|
||||
select {
|
||||
case msg := <-messages:
|
||||
fmt.Println("received message", msg)
|
||||
case sig := <-signals:
|
||||
fmt.Println("received signal", sig)
|
||||
default:
|
||||
fmt.Println("no activity")
|
||||
}
|
||||
// We can use multiple `case`s above the `default`
|
||||
// clause to implement a multi-way non-blocking
|
||||
// select. Here we attempt non-blocking receives
|
||||
// on both `messages` and `signals`.
|
||||
select {
|
||||
case msg := <-messages:
|
||||
fmt.Println("received message", msg)
|
||||
case sig := <-signals:
|
||||
fmt.Println("received signal", sig)
|
||||
default:
|
||||
fmt.Println("no activity")
|
||||
}
|
||||
}
|
||||
|
@ -10,31 +10,31 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// With `ParseFloat`, this `64` tells how many bits of
|
||||
// precision to parse.
|
||||
f, _ := strconv.ParseFloat("1.234", 64)
|
||||
fmt.Println(f)
|
||||
// With `ParseFloat`, this `64` tells how many bits of
|
||||
// precision to parse.
|
||||
f, _ := strconv.ParseFloat("1.234", 64)
|
||||
fmt.Println(f)
|
||||
|
||||
// For `ParseInt`, the `0` means infer the base from
|
||||
// the string. `64` requires that the result fit in 64
|
||||
// bits.
|
||||
i, _ := strconv.ParseInt("123", 0, 64)
|
||||
fmt.Println(i)
|
||||
// For `ParseInt`, the `0` means infer the base from
|
||||
// the string. `64` requires that the result fit in 64
|
||||
// bits.
|
||||
i, _ := strconv.ParseInt("123", 0, 64)
|
||||
fmt.Println(i)
|
||||
|
||||
// `ParseInt` will recognize hex-formatted numbers.
|
||||
d, _ := strconv.ParseInt("0x1c8", 0, 64)
|
||||
fmt.Println(d)
|
||||
// `ParseInt` will recognize hex-formatted numbers.
|
||||
d, _ := strconv.ParseInt("0x1c8", 0, 64)
|
||||
fmt.Println(d)
|
||||
|
||||
// A `ParseUint` is also available.
|
||||
u, _ := strconv.ParseUint("789", 0, 64)
|
||||
fmt.Println(u)
|
||||
// A `ParseUint` is also available.
|
||||
u, _ := strconv.ParseUint("789", 0, 64)
|
||||
fmt.Println(u)
|
||||
|
||||
// `Atoi` is a convenience function for basic base-10
|
||||
// `int` parsing.
|
||||
k, _ := strconv.Atoi("135")
|
||||
fmt.Println(k)
|
||||
// `Atoi` is a convenience function for basic base-10
|
||||
// `int` parsing.
|
||||
k, _ := strconv.Atoi("135")
|
||||
fmt.Println(k)
|
||||
|
||||
// Parse functions return an error on bad input.
|
||||
_, e := strconv.Atoi("wat")
|
||||
fmt.Println(e)
|
||||
// Parse functions return an error on bad input.
|
||||
_, e := strconv.Atoi("wat")
|
||||
fmt.Println(e)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
0d2155e9863a73c098d44637e92403d7f5e8e965
|
||||
N90EppECFk
|
||||
NZh4LjhguvN
|
||||
|
@ -9,17 +9,17 @@ import "os"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll use panic throughout this site to check for
|
||||
// unexpected errors. This is the only program on the
|
||||
// site designed to panic.
|
||||
panic("a problem")
|
||||
// We'll use panic throughout this site to check for
|
||||
// unexpected errors. This is the only program on the
|
||||
// site designed to panic.
|
||||
panic("a problem")
|
||||
|
||||
// A common use of panic is to abort if a function
|
||||
// returns an error value that we don't know how to
|
||||
// (or want to) handle. Here's an example of
|
||||
// `panic`king if we get an unexpected error when creating a new file.
|
||||
_, err := os.Create("/tmp/file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// A common use of panic is to abort if a function
|
||||
// returns an error value that we don't know how to
|
||||
// (or want to) handle. Here's an example of
|
||||
// `panic`king if we get an unexpected error when creating a new file.
|
||||
_, err := os.Create("/tmp/file")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
91639bbcfcc6ed088295a9ee6b1c36ab35ae402a
|
||||
c86oXzfQOt
|
||||
91HXbZZZopt
|
||||
|
@ -12,7 +12,7 @@ import "fmt"
|
||||
// value. `zeroval` will get a copy of `ival` distinct
|
||||
// from the one in the calling function.
|
||||
func zeroval(ival int) {
|
||||
ival = 0
|
||||
ival = 0
|
||||
}
|
||||
|
||||
// `zeroptr` in contrast has an `*int` parameter, meaning
|
||||
@ -22,21 +22,21 @@ func zeroval(ival int) {
|
||||
// Assigning a value to a dereferenced pointer changes the
|
||||
// value at the referenced address.
|
||||
func zeroptr(iptr *int) {
|
||||
*iptr = 0
|
||||
*iptr = 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
i := 1
|
||||
fmt.Println("initial:", i)
|
||||
i := 1
|
||||
fmt.Println("initial:", i)
|
||||
|
||||
zeroval(i)
|
||||
fmt.Println("zeroval:", i)
|
||||
zeroval(i)
|
||||
fmt.Println("zeroval:", i)
|
||||
|
||||
// The `&i` syntax gives the memory address of `i`,
|
||||
// i.e. a pointer to `i`.
|
||||
zeroptr(&i)
|
||||
fmt.Println("zeroptr:", i)
|
||||
// The `&i` syntax gives the memory address of `i`,
|
||||
// i.e. a pointer to `i`.
|
||||
zeroptr(&i)
|
||||
fmt.Println("zeroptr:", i)
|
||||
|
||||
// Pointers can be printed too.
|
||||
fmt.Println("pointer:", &i)
|
||||
// Pointers can be printed too.
|
||||
fmt.Println("pointer:", &i)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
85cff3345d2f22b65a5d54eb8f7aa8f508f27887
|
||||
KdE4TBbUL2
|
||||
fnQkHp4hriG
|
||||
|
@ -10,45 +10,45 @@ import "math/rand"
|
||||
|
||||
func main() {
|
||||
|
||||
// For example, `rand.Intn` returns a random `int` n,
|
||||
// `0 <= n < 100`.
|
||||
fmt.Print(rand.Intn(100), ",")
|
||||
fmt.Print(rand.Intn(100))
|
||||
fmt.Println()
|
||||
// For example, `rand.Intn` returns a random `int` n,
|
||||
// `0 <= n < 100`.
|
||||
fmt.Print(rand.Intn(100), ",")
|
||||
fmt.Print(rand.Intn(100))
|
||||
fmt.Println()
|
||||
|
||||
// `rand.Float64` returns a `float64` `f`,
|
||||
// `0.0 <= f < 1.0`.
|
||||
fmt.Println(rand.Float64())
|
||||
// `rand.Float64` returns a `float64` `f`,
|
||||
// `0.0 <= f < 1.0`.
|
||||
fmt.Println(rand.Float64())
|
||||
|
||||
// This can be used to generate random floats in
|
||||
// other ranges, for example `5.0 <= f' < 10.0`.
|
||||
fmt.Print((rand.Float64()*5)+5, ",")
|
||||
fmt.Print((rand.Float64() * 5) + 5)
|
||||
fmt.Println()
|
||||
// This can be used to generate random floats in
|
||||
// other ranges, for example `5.0 <= f' < 10.0`.
|
||||
fmt.Print((rand.Float64()*5)+5, ",")
|
||||
fmt.Print((rand.Float64() * 5) + 5)
|
||||
fmt.Println()
|
||||
|
||||
// The default number generator is deterministic, so it'll
|
||||
// produce the same sequence of numbers each time by default.
|
||||
// To produce varying sequences, give it a seed that changes.
|
||||
// Note that this is not safe to use for random numbers you
|
||||
// intend to be secret, use `crypto/rand` for those.
|
||||
s1 := rand.NewSource(time.Now().UnixNano())
|
||||
r1 := rand.New(s1)
|
||||
// The default number generator is deterministic, so it'll
|
||||
// produce the same sequence of numbers each time by default.
|
||||
// To produce varying sequences, give it a seed that changes.
|
||||
// Note that this is not safe to use for random numbers you
|
||||
// intend to be secret, use `crypto/rand` for those.
|
||||
s1 := rand.NewSource(time.Now().UnixNano())
|
||||
r1 := rand.New(s1)
|
||||
|
||||
// Call the resulting `rand.Rand` just like the
|
||||
// functions on the `rand` package.
|
||||
fmt.Print(r1.Intn(100), ",")
|
||||
fmt.Print(r1.Intn(100))
|
||||
fmt.Println()
|
||||
// Call the resulting `rand.Rand` just like the
|
||||
// functions on the `rand` package.
|
||||
fmt.Print(r1.Intn(100), ",")
|
||||
fmt.Print(r1.Intn(100))
|
||||
fmt.Println()
|
||||
|
||||
// If you seed a source with the same number, it
|
||||
// produces the same sequence of random numbers.
|
||||
s2 := rand.NewSource(42)
|
||||
r2 := rand.New(s2)
|
||||
fmt.Print(r2.Intn(100), ",")
|
||||
fmt.Print(r2.Intn(100))
|
||||
fmt.Println()
|
||||
s3 := rand.NewSource(42)
|
||||
r3 := rand.New(s3)
|
||||
fmt.Print(r3.Intn(100), ",")
|
||||
fmt.Print(r3.Intn(100))
|
||||
// If you seed a source with the same number, it
|
||||
// produces the same sequence of random numbers.
|
||||
s2 := rand.NewSource(42)
|
||||
r2 := rand.New(s2)
|
||||
fmt.Print(r2.Intn(100), ",")
|
||||
fmt.Print(r2.Intn(100))
|
||||
fmt.Println()
|
||||
s3 := rand.NewSource(42)
|
||||
r3 := rand.New(s3)
|
||||
fmt.Print(r3.Intn(100), ",")
|
||||
fmt.Print(r3.Intn(100))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
8e97de760147b061dd09939db294c892211b6b80
|
||||
ZdFpbahgC1
|
||||
jiJaIjxL2sP
|
||||
|
@ -9,17 +9,17 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll iterate over 2 values in the `queue` channel.
|
||||
queue := make(chan string, 2)
|
||||
queue <- "one"
|
||||
queue <- "two"
|
||||
close(queue)
|
||||
// We'll iterate over 2 values in the `queue` channel.
|
||||
queue := make(chan string, 2)
|
||||
queue <- "one"
|
||||
queue <- "two"
|
||||
close(queue)
|
||||
|
||||
// This `range` iterates over each element as it's
|
||||
// received from `queue`. Because we `close`d the
|
||||
// channel above, the iteration terminates after
|
||||
// receiving the 2 elements.
|
||||
for elem := range queue {
|
||||
fmt.Println(elem)
|
||||
}
|
||||
// This `range` iterates over each element as it's
|
||||
// received from `queue`. Because we `close`d the
|
||||
// channel above, the iteration terminates after
|
||||
// receiving the 2 elements.
|
||||
for elem := range queue {
|
||||
fmt.Println(elem)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
8b5d8a77e84c34771c5b14af014ecef3f88b2a6c
|
||||
I63ge2ISDs
|
||||
QnARPm-ddFB
|
||||
|
@ -8,41 +8,41 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here we use `range` to sum the numbers in a slice.
|
||||
// Arrays work like this too.
|
||||
nums := []int{2, 3, 4}
|
||||
sum := 0
|
||||
for _, num := range nums {
|
||||
sum += num
|
||||
}
|
||||
fmt.Println("sum:", sum)
|
||||
// Here we use `range` to sum the numbers in a slice.
|
||||
// Arrays work like this too.
|
||||
nums := []int{2, 3, 4}
|
||||
sum := 0
|
||||
for _, num := range nums {
|
||||
sum += num
|
||||
}
|
||||
fmt.Println("sum:", sum)
|
||||
|
||||
// `range` on arrays and slices provides both the
|
||||
// index and value for each entry. Above we didn't
|
||||
// need the index, so we ignored it with the
|
||||
// blank identifier `_`. Sometimes we actually want
|
||||
// the indexes though.
|
||||
for i, num := range nums {
|
||||
if num == 3 {
|
||||
fmt.Println("index:", i)
|
||||
}
|
||||
}
|
||||
// `range` on arrays and slices provides both the
|
||||
// index and value for each entry. Above we didn't
|
||||
// need the index, so we ignored it with the
|
||||
// blank identifier `_`. Sometimes we actually want
|
||||
// the indexes though.
|
||||
for i, num := range nums {
|
||||
if num == 3 {
|
||||
fmt.Println("index:", i)
|
||||
}
|
||||
}
|
||||
|
||||
// `range` on map iterates over key/value pairs.
|
||||
kvs := map[string]string{"a": "apple", "b": "banana"}
|
||||
for k, v := range kvs {
|
||||
fmt.Printf("%s -> %s\n", k, v)
|
||||
}
|
||||
// `range` on map iterates over key/value pairs.
|
||||
kvs := map[string]string{"a": "apple", "b": "banana"}
|
||||
for k, v := range kvs {
|
||||
fmt.Printf("%s -> %s\n", k, v)
|
||||
}
|
||||
|
||||
// `range` can also iterate over just the keys of a map.
|
||||
for k := range kvs {
|
||||
fmt.Println("key:", k)
|
||||
}
|
||||
// `range` can also iterate over just the keys of a map.
|
||||
for k := range kvs {
|
||||
fmt.Println("key:", k)
|
||||
}
|
||||
|
||||
// `range` on strings iterates over Unicode code
|
||||
// points. The first value is the starting byte index
|
||||
// of the `rune` and the second the `rune` itself.
|
||||
for i, c := range "go" {
|
||||
fmt.Println(i, c)
|
||||
}
|
||||
// `range` on strings iterates over Unicode code
|
||||
// points. The first value is the starting byte index
|
||||
// of the `rune` and the second the `rune` itself.
|
||||
for i, c := range "go" {
|
||||
fmt.Println(i, c)
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
ebe328a57f3d34708709ca99d3304af1733592d9
|
||||
SkL_AS-1Jd
|
||||
JTY1VAUjfBw
|
||||
|
@ -11,59 +11,59 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// First we'll look at basic rate limiting. Suppose
|
||||
// we want to limit our handling of incoming requests.
|
||||
// We'll serve these requests off a channel of the
|
||||
// same name.
|
||||
requests := make(chan int, 5)
|
||||
for i := 1; i <= 5; i++ {
|
||||
requests <- i
|
||||
}
|
||||
close(requests)
|
||||
// First we'll look at basic rate limiting. Suppose
|
||||
// we want to limit our handling of incoming requests.
|
||||
// We'll serve these requests off a channel of the
|
||||
// same name.
|
||||
requests := make(chan int, 5)
|
||||
for i := 1; i <= 5; i++ {
|
||||
requests <- i
|
||||
}
|
||||
close(requests)
|
||||
|
||||
// This `limiter` channel will receive a value
|
||||
// every 200 milliseconds. This is the regulator in
|
||||
// our rate limiting scheme.
|
||||
limiter := time.Tick(200 * time.Millisecond)
|
||||
// This `limiter` channel will receive a value
|
||||
// every 200 milliseconds. This is the regulator in
|
||||
// our rate limiting scheme.
|
||||
limiter := time.Tick(200 * time.Millisecond)
|
||||
|
||||
// By blocking on a receive from the `limiter` channel
|
||||
// before serving each request, we limit ourselves to
|
||||
// 1 request every 200 milliseconds.
|
||||
for req := range requests {
|
||||
<-limiter
|
||||
fmt.Println("request", req, time.Now())
|
||||
}
|
||||
// By blocking on a receive from the `limiter` channel
|
||||
// before serving each request, we limit ourselves to
|
||||
// 1 request every 200 milliseconds.
|
||||
for req := range requests {
|
||||
<-limiter
|
||||
fmt.Println("request", req, time.Now())
|
||||
}
|
||||
|
||||
// We may want to allow short bursts of requests in
|
||||
// our rate limiting scheme while preserving the
|
||||
// overall rate limit. We can accomplish this by
|
||||
// buffering our limiter channel. This `burstyLimiter`
|
||||
// channel will allow bursts of up to 3 events.
|
||||
burstyLimiter := make(chan time.Time, 3)
|
||||
// We may want to allow short bursts of requests in
|
||||
// our rate limiting scheme while preserving the
|
||||
// overall rate limit. We can accomplish this by
|
||||
// buffering our limiter channel. This `burstyLimiter`
|
||||
// channel will allow bursts of up to 3 events.
|
||||
burstyLimiter := make(chan time.Time, 3)
|
||||
|
||||
// Fill up the channel to represent allowed bursting.
|
||||
for i := 0; i < 3; i++ {
|
||||
burstyLimiter <- time.Now()
|
||||
}
|
||||
// Fill up the channel to represent allowed bursting.
|
||||
for i := 0; i < 3; i++ {
|
||||
burstyLimiter <- time.Now()
|
||||
}
|
||||
|
||||
// Every 200 milliseconds we'll try to add a new
|
||||
// value to `burstyLimiter`, up to its limit of 3.
|
||||
go func() {
|
||||
for t := range time.Tick(200 * time.Millisecond) {
|
||||
burstyLimiter <- t
|
||||
}
|
||||
}()
|
||||
// Every 200 milliseconds we'll try to add a new
|
||||
// value to `burstyLimiter`, up to its limit of 3.
|
||||
go func() {
|
||||
for t := range time.Tick(200 * time.Millisecond) {
|
||||
burstyLimiter <- t
|
||||
}
|
||||
}()
|
||||
|
||||
// Now simulate 5 more incoming requests. The first
|
||||
// 3 of these will benefit from the burst capability
|
||||
// of `burstyLimiter`.
|
||||
burstyRequests := make(chan int, 5)
|
||||
for i := 1; i <= 5; i++ {
|
||||
burstyRequests <- i
|
||||
}
|
||||
close(burstyRequests)
|
||||
for req := range burstyRequests {
|
||||
<-burstyLimiter
|
||||
fmt.Println("request", req, time.Now())
|
||||
}
|
||||
// Now simulate 5 more incoming requests. The first
|
||||
// 3 of these will benefit from the burst capability
|
||||
// of `burstyLimiter`.
|
||||
burstyRequests := make(chan int, 5)
|
||||
for i := 1; i <= 5; i++ {
|
||||
burstyRequests <- i
|
||||
}
|
||||
close(burstyRequests)
|
||||
for req := range burstyRequests {
|
||||
<-burstyLimiter
|
||||
fmt.Println("request", req, time.Now())
|
||||
}
|
||||
}
|
||||
|
@ -5,80 +5,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Reading files requires checking most calls for errors.
|
||||
// This helper will streamline our error checks below.
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Perhaps the most basic file reading task is
|
||||
// slurping a file's entire contents into memory.
|
||||
dat, err := ioutil.ReadFile("/tmp/dat")
|
||||
check(err)
|
||||
fmt.Print(string(dat))
|
||||
// Perhaps the most basic file reading task is
|
||||
// slurping a file's entire contents into memory.
|
||||
dat, err := ioutil.ReadFile("/tmp/dat")
|
||||
check(err)
|
||||
fmt.Print(string(dat))
|
||||
|
||||
// You'll often want more control over how and what
|
||||
// parts of a file are read. For these tasks, start
|
||||
// by `Open`ing a file to obtain an `os.File` value.
|
||||
f, err := os.Open("/tmp/dat")
|
||||
check(err)
|
||||
// You'll often want more control over how and what
|
||||
// parts of a file are read. For these tasks, start
|
||||
// by `Open`ing a file to obtain an `os.File` value.
|
||||
f, err := os.Open("/tmp/dat")
|
||||
check(err)
|
||||
|
||||
// Read some bytes from the beginning of the file.
|
||||
// Allow up to 5 to be read but also note how many
|
||||
// actually were read.
|
||||
b1 := make([]byte, 5)
|
||||
n1, err := f.Read(b1)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes: %s\n", n1, string(b1))
|
||||
// Read some bytes from the beginning of the file.
|
||||
// Allow up to 5 to be read but also note how many
|
||||
// actually were read.
|
||||
b1 := make([]byte, 5)
|
||||
n1, err := f.Read(b1)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes: %s\n", n1, string(b1))
|
||||
|
||||
// You can also `Seek` to a known location in the file
|
||||
// and `Read` from there.
|
||||
o2, err := f.Seek(6, 0)
|
||||
check(err)
|
||||
b2 := make([]byte, 2)
|
||||
n2, err := f.Read(b2)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2))
|
||||
// You can also `Seek` to a known location in the file
|
||||
// and `Read` from there.
|
||||
o2, err := f.Seek(6, 0)
|
||||
check(err)
|
||||
b2 := make([]byte, 2)
|
||||
n2, err := f.Read(b2)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2))
|
||||
|
||||
// The `io` package provides some functions that may
|
||||
// be helpful for file reading. For example, reads
|
||||
// like the ones above can be more robustly
|
||||
// implemented with `ReadAtLeast`.
|
||||
o3, err := f.Seek(6, 0)
|
||||
check(err)
|
||||
b3 := make([]byte, 2)
|
||||
n3, err := io.ReadAtLeast(f, b3, 2)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
|
||||
// The `io` package provides some functions that may
|
||||
// be helpful for file reading. For example, reads
|
||||
// like the ones above can be more robustly
|
||||
// implemented with `ReadAtLeast`.
|
||||
o3, err := f.Seek(6, 0)
|
||||
check(err)
|
||||
b3 := make([]byte, 2)
|
||||
n3, err := io.ReadAtLeast(f, b3, 2)
|
||||
check(err)
|
||||
fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3))
|
||||
|
||||
// There is no built-in rewind, but `Seek(0, 0)`
|
||||
// accomplishes this.
|
||||
_, err = f.Seek(0, 0)
|
||||
check(err)
|
||||
// There is no built-in rewind, but `Seek(0, 0)`
|
||||
// accomplishes this.
|
||||
_, err = f.Seek(0, 0)
|
||||
check(err)
|
||||
|
||||
// The `bufio` package implements a buffered
|
||||
// reader that may be useful both for its efficiency
|
||||
// with many small reads and because of the additional
|
||||
// reading methods it provides.
|
||||
r4 := bufio.NewReader(f)
|
||||
b4, err := r4.Peek(5)
|
||||
check(err)
|
||||
fmt.Printf("5 bytes: %s\n", string(b4))
|
||||
// The `bufio` package implements a buffered
|
||||
// reader that may be useful both for its efficiency
|
||||
// with many small reads and because of the additional
|
||||
// reading methods it provides.
|
||||
r4 := bufio.NewReader(f)
|
||||
b4, err := r4.Peek(5)
|
||||
check(err)
|
||||
fmt.Printf("5 bytes: %s\n", string(b4))
|
||||
|
||||
// Close the file when you're done (usually this would
|
||||
// be scheduled immediately after `Open`ing with
|
||||
// `defer`).
|
||||
f.Close()
|
||||
// Close the file when you're done (usually this would
|
||||
// be scheduled immediately after `Open`ing with
|
||||
// `defer`).
|
||||
f.Close()
|
||||
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
2aa7a2e248065cebfa6f8eece3234b5ffa710273
|
||||
2kEKXq-kUV
|
||||
GQgp-I3dLb2
|
||||
|
@ -9,12 +9,12 @@ import "fmt"
|
||||
// This `fact` function calls itself until it reaches the
|
||||
// base case of `fact(0)`.
|
||||
func fact(n int) int {
|
||||
if n == 0 {
|
||||
return 1
|
||||
}
|
||||
return n * fact(n-1)
|
||||
if n == 0 {
|
||||
return 1
|
||||
}
|
||||
return n * fact(n-1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(fact(7))
|
||||
fmt.Println(fact(7))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
5d1ba6b03a50ccae2a0f46865eb72c587e11857c
|
||||
RFn-rf42ap
|
||||
4yUp5wLVyiG
|
||||
|
@ -10,72 +10,72 @@ import "regexp"
|
||||
|
||||
func main() {
|
||||
|
||||
// This tests whether a pattern matches a string.
|
||||
match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
|
||||
fmt.Println(match)
|
||||
// This tests whether a pattern matches a string.
|
||||
match, _ := regexp.MatchString("p([a-z]+)ch", "peach")
|
||||
fmt.Println(match)
|
||||
|
||||
// Above we used a string pattern directly, but for
|
||||
// other regexp tasks you'll need to `Compile` an
|
||||
// optimized `Regexp` struct.
|
||||
r, _ := regexp.Compile("p([a-z]+)ch")
|
||||
// Above we used a string pattern directly, but for
|
||||
// other regexp tasks you'll need to `Compile` an
|
||||
// optimized `Regexp` struct.
|
||||
r, _ := regexp.Compile("p([a-z]+)ch")
|
||||
|
||||
// Many methods are available on these structs. Here's
|
||||
// a match test like we saw earlier.
|
||||
fmt.Println(r.MatchString("peach"))
|
||||
// Many methods are available on these structs. Here's
|
||||
// a match test like we saw earlier.
|
||||
fmt.Println(r.MatchString("peach"))
|
||||
|
||||
// This finds the match for the regexp.
|
||||
fmt.Println(r.FindString("peach punch"))
|
||||
// This finds the match for the regexp.
|
||||
fmt.Println(r.FindString("peach punch"))
|
||||
|
||||
// This also finds the first match but returns the
|
||||
// start and end indexes for the match instead of the
|
||||
// matching text.
|
||||
fmt.Println(r.FindStringIndex("peach punch"))
|
||||
// This also finds the first match but returns the
|
||||
// start and end indexes for the match instead of the
|
||||
// matching text.
|
||||
fmt.Println(r.FindStringIndex("peach punch"))
|
||||
|
||||
// The `Submatch` variants include information about
|
||||
// both the whole-pattern matches and the submatches
|
||||
// within those matches. For example this will return
|
||||
// information for both `p([a-z]+)ch` and `([a-z]+)`.
|
||||
fmt.Println(r.FindStringSubmatch("peach punch"))
|
||||
// The `Submatch` variants include information about
|
||||
// both the whole-pattern matches and the submatches
|
||||
// within those matches. For example this will return
|
||||
// information for both `p([a-z]+)ch` and `([a-z]+)`.
|
||||
fmt.Println(r.FindStringSubmatch("peach punch"))
|
||||
|
||||
// Similarly this will return information about the
|
||||
// indexes of matches and submatches.
|
||||
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
|
||||
// Similarly this will return information about the
|
||||
// indexes of matches and submatches.
|
||||
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
|
||||
|
||||
// The `All` variants of these functions apply to all
|
||||
// matches in the input, not just the first. For
|
||||
// example to find all matches for a regexp.
|
||||
fmt.Println(r.FindAllString("peach punch pinch", -1))
|
||||
// The `All` variants of these functions apply to all
|
||||
// matches in the input, not just the first. For
|
||||
// example to find all matches for a regexp.
|
||||
fmt.Println(r.FindAllString("peach punch pinch", -1))
|
||||
|
||||
// These `All` variants are available for the other
|
||||
// functions we saw above as well.
|
||||
fmt.Println(r.FindAllStringSubmatchIndex(
|
||||
"peach punch pinch", -1))
|
||||
// These `All` variants are available for the other
|
||||
// functions we saw above as well.
|
||||
fmt.Println(r.FindAllStringSubmatchIndex(
|
||||
"peach punch pinch", -1))
|
||||
|
||||
// Providing a non-negative integer as the second
|
||||
// argument to these functions will limit the number
|
||||
// of matches.
|
||||
fmt.Println(r.FindAllString("peach punch pinch", 2))
|
||||
// Providing a non-negative integer as the second
|
||||
// argument to these functions will limit the number
|
||||
// of matches.
|
||||
fmt.Println(r.FindAllString("peach punch pinch", 2))
|
||||
|
||||
// Our examples above had string arguments and used
|
||||
// names like `MatchString`. We can also provide
|
||||
// `[]byte` arguments and drop `String` from the
|
||||
// function name.
|
||||
fmt.Println(r.Match([]byte("peach")))
|
||||
// Our examples above had string arguments and used
|
||||
// names like `MatchString`. We can also provide
|
||||
// `[]byte` arguments and drop `String` from the
|
||||
// function name.
|
||||
fmt.Println(r.Match([]byte("peach")))
|
||||
|
||||
// When creating constants with regular expressions
|
||||
// you can use the `MustCompile` variation of
|
||||
// `Compile`. A plain `Compile` won't work for
|
||||
// constants because it has 2 return values.
|
||||
r = regexp.MustCompile("p([a-z]+)ch")
|
||||
fmt.Println(r)
|
||||
// When creating constants with regular expressions
|
||||
// you can use the `MustCompile` variation of
|
||||
// `Compile`. A plain `Compile` won't work for
|
||||
// constants because it has 2 return values.
|
||||
r = regexp.MustCompile("p([a-z]+)ch")
|
||||
fmt.Println(r)
|
||||
|
||||
// The `regexp` package can also be used to replace
|
||||
// subsets of strings with other values.
|
||||
fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
|
||||
// The `regexp` package can also be used to replace
|
||||
// subsets of strings with other values.
|
||||
fmt.Println(r.ReplaceAllString("a peach", "<fruit>"))
|
||||
|
||||
// The `Func` variant allows you to transform matched
|
||||
// text with a given function.
|
||||
in := []byte("a peach")
|
||||
out := r.ReplaceAllFunc(in, bytes.ToUpper)
|
||||
fmt.Println(string(out))
|
||||
// The `Func` variant allows you to transform matched
|
||||
// text with a given function.
|
||||
in := []byte("a peach")
|
||||
out := r.ReplaceAllFunc(in, bytes.ToUpper)
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
7cde6b9af5cf6c47606001dd54eee468a6c61dbb
|
||||
YeSiBTfhFq
|
||||
qR5gn2l0AGa
|
||||
|
@ -9,30 +9,30 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// For our example we'll select across two channels.
|
||||
c1 := make(chan string)
|
||||
c2 := make(chan string)
|
||||
// For our example we'll select across two channels.
|
||||
c1 := make(chan string)
|
||||
c2 := make(chan string)
|
||||
|
||||
// Each channel will receive a value after some amount
|
||||
// of time, to simulate e.g. blocking RPC operations
|
||||
// executing in concurrent goroutines.
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
c1 <- "one"
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c2 <- "two"
|
||||
}()
|
||||
// Each channel will receive a value after some amount
|
||||
// of time, to simulate e.g. blocking RPC operations
|
||||
// executing in concurrent goroutines.
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
c1 <- "one"
|
||||
}()
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c2 <- "two"
|
||||
}()
|
||||
|
||||
// We'll use `select` to await both of these values
|
||||
// simultaneously, printing each one as it arrives.
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case msg1 := <-c1:
|
||||
fmt.Println("received", msg1)
|
||||
case msg2 := <-c2:
|
||||
fmt.Println("received", msg2)
|
||||
}
|
||||
}
|
||||
// We'll use `select` to await both of these values
|
||||
// simultaneously, printing each one as it arrives.
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case msg1 := <-c1:
|
||||
fmt.Println("received", msg1)
|
||||
case msg2 := <-c2:
|
||||
fmt.Println("received", msg2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,25 +13,25 @@ import "crypto/sha1"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
s := "sha1 this string"
|
||||
s := "sha1 this string"
|
||||
|
||||
// The pattern for generating a hash is `sha1.New()`,
|
||||
// `sha1.Write(bytes)`, then `sha1.Sum([]byte{})`.
|
||||
// Here we start with a new hash.
|
||||
h := sha1.New()
|
||||
// The pattern for generating a hash is `sha1.New()`,
|
||||
// `sha1.Write(bytes)`, then `sha1.Sum([]byte{})`.
|
||||
// Here we start with a new hash.
|
||||
h := sha1.New()
|
||||
|
||||
// `Write` expects bytes. If you have a string `s`,
|
||||
// use `[]byte(s)` to coerce it to bytes.
|
||||
h.Write([]byte(s))
|
||||
// `Write` expects bytes. If you have a string `s`,
|
||||
// use `[]byte(s)` to coerce it to bytes.
|
||||
h.Write([]byte(s))
|
||||
|
||||
// This gets the finalized hash result as a byte
|
||||
// slice. The argument to `Sum` can be used to append
|
||||
// to an existing byte slice: it usually isn't needed.
|
||||
bs := h.Sum(nil)
|
||||
// This gets the finalized hash result as a byte
|
||||
// slice. The argument to `Sum` can be used to append
|
||||
// to an existing byte slice: it usually isn't needed.
|
||||
bs := h.Sum(nil)
|
||||
|
||||
// SHA1 values are often printed in hex, for example
|
||||
// in git commits. Use the `%x` format verb to convert
|
||||
// a hash results to a hex string.
|
||||
fmt.Println(s)
|
||||
fmt.Printf("%x\n", bs)
|
||||
// SHA1 values are often printed in hex, for example
|
||||
// in git commits. Use the `%x` format verb to convert
|
||||
// a hash results to a hex string.
|
||||
fmt.Println(s)
|
||||
fmt.Printf("%x\n", bs)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
6a896270e34f2696b881a8fa7e68bfff57dee51f
|
||||
YUaWWEeB4U
|
||||
1oT-5GBUkLr
|
||||
|
@ -14,31 +14,31 @@ import "syscall"
|
||||
|
||||
func main() {
|
||||
|
||||
// Go signal notification works by sending `os.Signal`
|
||||
// values on a channel. We'll create a channel to
|
||||
// receive these notifications (we'll also make one to
|
||||
// notify us when the program can exit).
|
||||
sigs := make(chan os.Signal, 1)
|
||||
done := make(chan bool, 1)
|
||||
// Go signal notification works by sending `os.Signal`
|
||||
// values on a channel. We'll create a channel to
|
||||
// receive these notifications (we'll also make one to
|
||||
// notify us when the program can exit).
|
||||
sigs := make(chan os.Signal, 1)
|
||||
done := make(chan bool, 1)
|
||||
|
||||
// `signal.Notify` registers the given channel to
|
||||
// receive notifications of the specified signals.
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
// `signal.Notify` registers the given channel to
|
||||
// receive notifications of the specified signals.
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// This goroutine executes a blocking receive for
|
||||
// signals. When it gets one it'll print it out
|
||||
// and then notify the program that it can finish.
|
||||
go func() {
|
||||
sig := <-sigs
|
||||
fmt.Println()
|
||||
fmt.Println(sig)
|
||||
done <- true
|
||||
}()
|
||||
// This goroutine executes a blocking receive for
|
||||
// signals. When it gets one it'll print it out
|
||||
// and then notify the program that it can finish.
|
||||
go func() {
|
||||
sig := <-sigs
|
||||
fmt.Println()
|
||||
fmt.Println(sig)
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// The program will wait here until it gets the
|
||||
// expected signal (as indicated by the goroutine
|
||||
// above sending a value on `done`) and then exit.
|
||||
fmt.Println("awaiting signal")
|
||||
<-done
|
||||
fmt.Println("exiting")
|
||||
// The program will wait here until it gets the
|
||||
// expected signal (as indicated by the goroutine
|
||||
// above sending a value on `done`) and then exit.
|
||||
fmt.Println("awaiting signal")
|
||||
<-done
|
||||
fmt.Println("exiting")
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
9720d747e3ab2893df508a70cbb341c90fdd7ca1
|
||||
BlkqAtKsxo
|
||||
9koJAW1raI5
|
||||
|
@ -7,70 +7,70 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Unlike arrays, slices are typed only by the
|
||||
// elements they contain (not the number of elements).
|
||||
// To create an empty slice with non-zero length, use
|
||||
// the builtin `make`. Here we make a slice of
|
||||
// `string`s of length `3` (initially zero-valued).
|
||||
s := make([]string, 3)
|
||||
fmt.Println("emp:", s)
|
||||
// Unlike arrays, slices are typed only by the
|
||||
// elements they contain (not the number of elements).
|
||||
// To create an empty slice with non-zero length, use
|
||||
// the builtin `make`. Here we make a slice of
|
||||
// `string`s of length `3` (initially zero-valued).
|
||||
s := make([]string, 3)
|
||||
fmt.Println("emp:", s)
|
||||
|
||||
// We can set and get just like with arrays.
|
||||
s[0] = "a"
|
||||
s[1] = "b"
|
||||
s[2] = "c"
|
||||
fmt.Println("set:", s)
|
||||
fmt.Println("get:", s[2])
|
||||
// We can set and get just like with arrays.
|
||||
s[0] = "a"
|
||||
s[1] = "b"
|
||||
s[2] = "c"
|
||||
fmt.Println("set:", s)
|
||||
fmt.Println("get:", s[2])
|
||||
|
||||
// `len` returns the length of the slice as expected.
|
||||
fmt.Println("len:", len(s))
|
||||
// `len` returns the length of the slice as expected.
|
||||
fmt.Println("len:", len(s))
|
||||
|
||||
// In addition to these basic operations, slices
|
||||
// support several more that make them richer than
|
||||
// arrays. One is the builtin `append`, which
|
||||
// returns a slice containing one or more new values.
|
||||
// Note that we need to accept a return value from
|
||||
// `append` as we may get a new slice value.
|
||||
s = append(s, "d")
|
||||
s = append(s, "e", "f")
|
||||
fmt.Println("apd:", s)
|
||||
// In addition to these basic operations, slices
|
||||
// support several more that make them richer than
|
||||
// arrays. One is the builtin `append`, which
|
||||
// returns a slice containing one or more new values.
|
||||
// Note that we need to accept a return value from
|
||||
// `append` as we may get a new slice value.
|
||||
s = append(s, "d")
|
||||
s = append(s, "e", "f")
|
||||
fmt.Println("apd:", s)
|
||||
|
||||
// Slices can also be `copy`'d. Here we create an
|
||||
// empty slice `c` of the same length as `s` and copy
|
||||
// into `c` from `s`.
|
||||
c := make([]string, len(s))
|
||||
copy(c, s)
|
||||
fmt.Println("cpy:", c)
|
||||
// Slices can also be `copy`'d. Here we create an
|
||||
// empty slice `c` of the same length as `s` and copy
|
||||
// into `c` from `s`.
|
||||
c := make([]string, len(s))
|
||||
copy(c, s)
|
||||
fmt.Println("cpy:", c)
|
||||
|
||||
// Slices support a "slice" operator with the syntax
|
||||
// `slice[low:high]`. For example, this gets a slice
|
||||
// of the elements `s[2]`, `s[3]`, and `s[4]`.
|
||||
l := s[2:5]
|
||||
fmt.Println("sl1:", l)
|
||||
// Slices support a "slice" operator with the syntax
|
||||
// `slice[low:high]`. For example, this gets a slice
|
||||
// of the elements `s[2]`, `s[3]`, and `s[4]`.
|
||||
l := s[2:5]
|
||||
fmt.Println("sl1:", l)
|
||||
|
||||
// This slices up to (but excluding) `s[5]`.
|
||||
l = s[:5]
|
||||
fmt.Println("sl2:", l)
|
||||
// This slices up to (but excluding) `s[5]`.
|
||||
l = s[:5]
|
||||
fmt.Println("sl2:", l)
|
||||
|
||||
// And this slices up from (and including) `s[2]`.
|
||||
l = s[2:]
|
||||
fmt.Println("sl3:", l)
|
||||
// And this slices up from (and including) `s[2]`.
|
||||
l = s[2:]
|
||||
fmt.Println("sl3:", l)
|
||||
|
||||
// We can declare and initialize a variable for slice
|
||||
// in a single line as well.
|
||||
t := []string{"g", "h", "i"}
|
||||
fmt.Println("dcl:", t)
|
||||
// We can declare and initialize a variable for slice
|
||||
// in a single line as well.
|
||||
t := []string{"g", "h", "i"}
|
||||
fmt.Println("dcl:", t)
|
||||
|
||||
// Slices can be composed into multi-dimensional data
|
||||
// structures. The length of the inner slices can
|
||||
// vary, unlike with multi-dimensional arrays.
|
||||
twoD := make([][]int, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
innerLen := i + 1
|
||||
twoD[i] = make([]int, innerLen)
|
||||
for j := 0; j < innerLen; j++ {
|
||||
twoD[i][j] = i + j
|
||||
}
|
||||
}
|
||||
fmt.Println("2d: ", twoD)
|
||||
// Slices can be composed into multi-dimensional data
|
||||
// structures. The length of the inner slices can
|
||||
// vary, unlike with multi-dimensional arrays.
|
||||
twoD := make([][]int, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
innerLen := i + 1
|
||||
twoD[i] = make([]int, innerLen)
|
||||
for j := 0; j < innerLen; j++ {
|
||||
twoD[i][j] = i + j
|
||||
}
|
||||
}
|
||||
fmt.Println("2d: ", twoD)
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ type byLength []string
|
||||
// want to sort in order of increasing string length, so
|
||||
// we use `len(s[i])` and `len(s[j])` here.
|
||||
func (s byLength) Len() int {
|
||||
return len(s)
|
||||
return len(s)
|
||||
}
|
||||
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 {
|
||||
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
|
||||
@ -37,7 +37,7 @@ func (s byLength) Less(i, j int) bool {
|
||||
// to `byLength`, and then use `sort.Sort` on that typed
|
||||
// slice.
|
||||
func main() {
|
||||
fruits := []string{"peach", "banana", "kiwi"}
|
||||
sort.Sort(byLength(fruits))
|
||||
fmt.Println(fruits)
|
||||
fruits := []string{"peach", "banana", "kiwi"}
|
||||
sort.Sort(byLength(fruits))
|
||||
fmt.Println(fruits)
|
||||
}
|
||||
|
@ -9,21 +9,21 @@ import "sort"
|
||||
|
||||
func main() {
|
||||
|
||||
// Sort methods are specific to the builtin type;
|
||||
// here's an example for strings. Note that sorting is
|
||||
// in-place, so it changes the given slice and doesn't
|
||||
// return a new one.
|
||||
strs := []string{"c", "a", "b"}
|
||||
sort.Strings(strs)
|
||||
fmt.Println("Strings:", strs)
|
||||
// Sort methods are specific to the builtin type;
|
||||
// here's an example for strings. Note that sorting is
|
||||
// in-place, so it changes the given slice and doesn't
|
||||
// return a new one.
|
||||
strs := []string{"c", "a", "b"}
|
||||
sort.Strings(strs)
|
||||
fmt.Println("Strings:", strs)
|
||||
|
||||
// An example of sorting `int`s.
|
||||
ints := []int{7, 2, 4}
|
||||
sort.Ints(ints)
|
||||
fmt.Println("Ints: ", ints)
|
||||
// An example of sorting `int`s.
|
||||
ints := []int{7, 2, 4}
|
||||
sort.Ints(ints)
|
||||
fmt.Println("Ints: ", ints)
|
||||
|
||||
// We can also use `sort` to check if a slice is
|
||||
// already in sorted order.
|
||||
s := sort.IntsAreSorted(ints)
|
||||
fmt.Println("Sorted: ", s)
|
||||
// We can also use `sort` to check if a slice is
|
||||
// already in sorted order.
|
||||
s := sort.IntsAreSorted(ints)
|
||||
fmt.Println("Sorted: ", s)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
4e576421f2bdbd11847c367d223bd30d0e301990
|
||||
roQOJXtqAb
|
||||
e6hp3Rn-oH6
|
||||
|
@ -13,59 +13,59 @@ import "os/exec"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll start with a simple command that takes no
|
||||
// arguments or input and just prints something to
|
||||
// stdout. The `exec.Command` helper creates an object
|
||||
// to represent this external process.
|
||||
dateCmd := exec.Command("date")
|
||||
// We'll start with a simple command that takes no
|
||||
// arguments or input and just prints something to
|
||||
// stdout. The `exec.Command` helper creates an object
|
||||
// to represent this external process.
|
||||
dateCmd := exec.Command("date")
|
||||
|
||||
// `.Output` is another helper that handles the common
|
||||
// case of running a command, waiting for it to finish,
|
||||
// and collecting its output. If there were no errors,
|
||||
// `dateOut` will hold bytes with the date info.
|
||||
dateOut, err := dateCmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("> date")
|
||||
fmt.Println(string(dateOut))
|
||||
// `.Output` is another helper that handles the common
|
||||
// case of running a command, waiting for it to finish,
|
||||
// and collecting its output. If there were no errors,
|
||||
// `dateOut` will hold bytes with the date info.
|
||||
dateOut, err := dateCmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("> date")
|
||||
fmt.Println(string(dateOut))
|
||||
|
||||
// Next we'll look at a slightly more involved case
|
||||
// where we pipe data to the external process on its
|
||||
// `stdin` and collect the results from its `stdout`.
|
||||
grepCmd := exec.Command("grep", "hello")
|
||||
// Next we'll look at a slightly more involved case
|
||||
// where we pipe data to the external process on its
|
||||
// `stdin` and collect the results from its `stdout`.
|
||||
grepCmd := exec.Command("grep", "hello")
|
||||
|
||||
// Here we explicitly grab input/output pipes, start
|
||||
// the process, write some input to it, read the
|
||||
// resulting output, and finally wait for the process
|
||||
// to exit.
|
||||
grepIn, _ := grepCmd.StdinPipe()
|
||||
grepOut, _ := grepCmd.StdoutPipe()
|
||||
grepCmd.Start()
|
||||
grepIn.Write([]byte("hello grep\ngoodbye grep"))
|
||||
grepIn.Close()
|
||||
grepBytes, _ := ioutil.ReadAll(grepOut)
|
||||
grepCmd.Wait()
|
||||
// Here we explicitly grab input/output pipes, start
|
||||
// the process, write some input to it, read the
|
||||
// resulting output, and finally wait for the process
|
||||
// to exit.
|
||||
grepIn, _ := grepCmd.StdinPipe()
|
||||
grepOut, _ := grepCmd.StdoutPipe()
|
||||
grepCmd.Start()
|
||||
grepIn.Write([]byte("hello grep\ngoodbye grep"))
|
||||
grepIn.Close()
|
||||
grepBytes, _ := ioutil.ReadAll(grepOut)
|
||||
grepCmd.Wait()
|
||||
|
||||
// We ommited error checks in the above example, but
|
||||
// you could use the usual `if err != nil` pattern for
|
||||
// all of them. We also only collect the `StdoutPipe`
|
||||
// results, but you could collect the `StderrPipe` in
|
||||
// exactly the same way.
|
||||
fmt.Println("> grep hello")
|
||||
fmt.Println(string(grepBytes))
|
||||
// We ommited error checks in the above example, but
|
||||
// you could use the usual `if err != nil` pattern for
|
||||
// all of them. We also only collect the `StdoutPipe`
|
||||
// results, but you could collect the `StderrPipe` in
|
||||
// exactly the same way.
|
||||
fmt.Println("> grep hello")
|
||||
fmt.Println(string(grepBytes))
|
||||
|
||||
// Note that when spawning commands we need to
|
||||
// provide an explicitly delineated command and
|
||||
// argument array, vs. being able to just pass in one
|
||||
// command-line string. If you want to spawn a full
|
||||
// command with a string, you can use `bash`'s `-c`
|
||||
// option:
|
||||
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
|
||||
lsOut, err := lsCmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("> ls -a -l -h")
|
||||
fmt.Println(string(lsOut))
|
||||
// Note that when spawning commands we need to
|
||||
// provide an explicitly delineated command and
|
||||
// argument array, vs. being able to just pass in one
|
||||
// command-line string. If you want to spawn a full
|
||||
// command with a string, you can use `bash`'s `-c`
|
||||
// option:
|
||||
lsCmd := exec.Command("bash", "-c", "ls -a -l -h")
|
||||
lsOut, err := lsCmd.Output()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("> ls -a -l -h")
|
||||
fmt.Println(string(lsOut))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
0b676b93e41ac5434003c194bc038d5f3ce76bc8
|
||||
y6SB6Mf2VQ
|
||||
6HRWVK5gPYU
|
||||
|
@ -10,10 +10,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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
|
||||
// goroutine to respond.
|
||||
type readOp struct {
|
||||
key int
|
||||
resp chan int
|
||||
key int
|
||||
resp chan int
|
||||
}
|
||||
type writeOp struct {
|
||||
key int
|
||||
val int
|
||||
resp chan bool
|
||||
key int
|
||||
val int
|
||||
resp chan bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// As before we'll count how many operations we perform.
|
||||
var readOps uint64
|
||||
var writeOps uint64
|
||||
// As before we'll count how many operations we perform.
|
||||
var readOps uint64
|
||||
var writeOps uint64
|
||||
|
||||
// The `reads` and `writes` channels will be used by
|
||||
// other goroutines to issue read and write requests,
|
||||
// respectively.
|
||||
reads := make(chan *readOp)
|
||||
writes := make(chan *writeOp)
|
||||
// The `reads` and `writes` channels will be used by
|
||||
// other goroutines to issue read and write requests,
|
||||
// respectively.
|
||||
reads := make(chan *readOp)
|
||||
writes := make(chan *writeOp)
|
||||
|
||||
// Here is the goroutine that owns the `state`, which
|
||||
// is a map as in the previous example but now private
|
||||
// to the stateful goroutine. This goroutine repeatedly
|
||||
// selects on the `reads` and `writes` channels,
|
||||
// responding to requests as they arrive. A response
|
||||
// is executed by first performing the requested
|
||||
// operation and then sending a value on the response
|
||||
// channel `resp` to indicate success (and the desired
|
||||
// value in the case of `reads`).
|
||||
go func() {
|
||||
var state = make(map[int]int)
|
||||
for {
|
||||
select {
|
||||
case read := <-reads:
|
||||
read.resp <- state[read.key]
|
||||
case write := <-writes:
|
||||
state[write.key] = write.val
|
||||
write.resp <- true
|
||||
}
|
||||
}
|
||||
}()
|
||||
// Here is the goroutine that owns the `state`, which
|
||||
// is a map as in the previous example but now private
|
||||
// to the stateful goroutine. This goroutine repeatedly
|
||||
// selects on the `reads` and `writes` channels,
|
||||
// responding to requests as they arrive. A response
|
||||
// is executed by first performing the requested
|
||||
// operation and then sending a value on the response
|
||||
// channel `resp` to indicate success (and the desired
|
||||
// value in the case of `reads`).
|
||||
go func() {
|
||||
var state = make(map[int]int)
|
||||
for {
|
||||
select {
|
||||
case read := <-reads:
|
||||
read.resp <- state[read.key]
|
||||
case write := <-writes:
|
||||
state[write.key] = write.val
|
||||
write.resp <- true
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// This starts 100 goroutines to issue reads to the
|
||||
// state-owning goroutine via the `reads` channel.
|
||||
// Each read requires constructing a `readOp`, sending
|
||||
// it over the `reads` channel, and the receiving the
|
||||
// result over the provided `resp` channel.
|
||||
for r := 0; r < 100; r++ {
|
||||
go func() {
|
||||
for {
|
||||
read := &readOp{
|
||||
key: rand.Intn(5),
|
||||
resp: make(chan int)}
|
||||
reads <- read
|
||||
<-read.resp
|
||||
atomic.AddUint64(&readOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// This starts 100 goroutines to issue reads to the
|
||||
// state-owning goroutine via the `reads` channel.
|
||||
// Each read requires constructing a `readOp`, sending
|
||||
// it over the `reads` channel, and the receiving the
|
||||
// result over the provided `resp` channel.
|
||||
for r := 0; r < 100; r++ {
|
||||
go func() {
|
||||
for {
|
||||
read := &readOp{
|
||||
key: rand.Intn(5),
|
||||
resp: make(chan int)}
|
||||
reads <- read
|
||||
<-read.resp
|
||||
atomic.AddUint64(&readOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// We start 10 writes as well, using a similar
|
||||
// approach.
|
||||
for w := 0; w < 10; w++ {
|
||||
go func() {
|
||||
for {
|
||||
write := &writeOp{
|
||||
key: rand.Intn(5),
|
||||
val: rand.Intn(100),
|
||||
resp: make(chan bool)}
|
||||
writes <- write
|
||||
<-write.resp
|
||||
atomic.AddUint64(&writeOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// We start 10 writes as well, using a similar
|
||||
// approach.
|
||||
for w := 0; w < 10; w++ {
|
||||
go func() {
|
||||
for {
|
||||
write := &writeOp{
|
||||
key: rand.Intn(5),
|
||||
val: rand.Intn(100),
|
||||
resp: make(chan bool)}
|
||||
writes <- write
|
||||
<-write.resp
|
||||
atomic.AddUint64(&writeOps, 1)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Let the goroutines work for a second.
|
||||
time.Sleep(time.Second)
|
||||
// Let the goroutines work for a second.
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// Finally, capture and report the op counts.
|
||||
readOpsFinal := atomic.LoadUint64(&readOps)
|
||||
fmt.Println("readOps:", readOpsFinal)
|
||||
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
||||
fmt.Println("writeOps:", writeOpsFinal)
|
||||
// Finally, capture and report the op counts.
|
||||
readOpsFinal := atomic.LoadUint64(&readOps)
|
||||
fmt.Println("readOps:", readOpsFinal)
|
||||
writeOpsFinal := atomic.LoadUint64(&writeOps)
|
||||
fmt.Println("writeOps:", writeOpsFinal)
|
||||
}
|
||||
|
@ -8,101 +8,101 @@ import "fmt"
|
||||
import "os"
|
||||
|
||||
type point struct {
|
||||
x, y int
|
||||
x, y int
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Go offers several printing "verbs" designed to
|
||||
// format general Go values. For example, this prints
|
||||
// an instance of our `point` struct.
|
||||
p := point{1, 2}
|
||||
fmt.Printf("%v\n", p)
|
||||
// Go offers several printing "verbs" designed to
|
||||
// format general Go values. For example, this prints
|
||||
// an instance of our `point` struct.
|
||||
p := point{1, 2}
|
||||
fmt.Printf("%v\n", p)
|
||||
|
||||
// If the value is a struct, the `%+v` variant will
|
||||
// include the struct's field names.
|
||||
fmt.Printf("%+v\n", p)
|
||||
// If the value is a struct, the `%+v` variant will
|
||||
// include the struct's field names.
|
||||
fmt.Printf("%+v\n", p)
|
||||
|
||||
// The `%#v` variant prints a Go syntax representation
|
||||
// of the value, i.e. the source code snippet that
|
||||
// would produce that value.
|
||||
fmt.Printf("%#v\n", p)
|
||||
// The `%#v` variant prints a Go syntax representation
|
||||
// of the value, i.e. the source code snippet that
|
||||
// would produce that value.
|
||||
fmt.Printf("%#v\n", p)
|
||||
|
||||
// To print the type of a value, use `%T`.
|
||||
fmt.Printf("%T\n", p)
|
||||
// To print the type of a value, use `%T`.
|
||||
fmt.Printf("%T\n", p)
|
||||
|
||||
// Formatting booleans is straight-forward.
|
||||
fmt.Printf("%t\n", true)
|
||||
// Formatting booleans is straight-forward.
|
||||
fmt.Printf("%t\n", true)
|
||||
|
||||
// There are many options for formatting integers.
|
||||
// Use `%d` for standard, base-10 formatting.
|
||||
fmt.Printf("%d\n", 123)
|
||||
// There are many options for formatting integers.
|
||||
// Use `%d` for standard, base-10 formatting.
|
||||
fmt.Printf("%d\n", 123)
|
||||
|
||||
// This prints a binary representation.
|
||||
fmt.Printf("%b\n", 14)
|
||||
// This prints a binary representation.
|
||||
fmt.Printf("%b\n", 14)
|
||||
|
||||
// This prints the character corresponding to the
|
||||
// given integer.
|
||||
fmt.Printf("%c\n", 33)
|
||||
// This prints the character corresponding to the
|
||||
// given integer.
|
||||
fmt.Printf("%c\n", 33)
|
||||
|
||||
// `%x` provides hex encoding.
|
||||
fmt.Printf("%x\n", 456)
|
||||
// `%x` provides hex encoding.
|
||||
fmt.Printf("%x\n", 456)
|
||||
|
||||
// There are also several formatting options for
|
||||
// floats. For basic decimal formatting use `%f`.
|
||||
fmt.Printf("%f\n", 78.9)
|
||||
// There are also several formatting options for
|
||||
// floats. For basic decimal formatting use `%f`.
|
||||
fmt.Printf("%f\n", 78.9)
|
||||
|
||||
// `%e` and `%E` format the float in (slightly
|
||||
// different versions of) scientific notation.
|
||||
fmt.Printf("%e\n", 123400000.0)
|
||||
fmt.Printf("%E\n", 123400000.0)
|
||||
// `%e` and `%E` format the float in (slightly
|
||||
// different versions of) scientific notation.
|
||||
fmt.Printf("%e\n", 123400000.0)
|
||||
fmt.Printf("%E\n", 123400000.0)
|
||||
|
||||
// For basic string printing use `%s`.
|
||||
fmt.Printf("%s\n", "\"string\"")
|
||||
// For basic string printing use `%s`.
|
||||
fmt.Printf("%s\n", "\"string\"")
|
||||
|
||||
// To double-quote strings as in Go source, use `%q`.
|
||||
fmt.Printf("%q\n", "\"string\"")
|
||||
// To double-quote strings as in Go source, use `%q`.
|
||||
fmt.Printf("%q\n", "\"string\"")
|
||||
|
||||
// As with integers seen earlier, `%x` renders
|
||||
// the string in base-16, with two output characters
|
||||
// per byte of input.
|
||||
fmt.Printf("%x\n", "hex this")
|
||||
// As with integers seen earlier, `%x` renders
|
||||
// the string in base-16, with two output characters
|
||||
// per byte of input.
|
||||
fmt.Printf("%x\n", "hex this")
|
||||
|
||||
// To print a representation of a pointer, use `%p`.
|
||||
fmt.Printf("%p\n", &p)
|
||||
// To print a representation of a pointer, use `%p`.
|
||||
fmt.Printf("%p\n", &p)
|
||||
|
||||
// When formatting numbers you will often want to
|
||||
// control the width and precision of the resulting
|
||||
// figure. To specify the width of an integer, use a
|
||||
// number after the `%` in the verb. By default the
|
||||
// result will be right-justified and padded with
|
||||
// spaces.
|
||||
fmt.Printf("|%6d|%6d|\n", 12, 345)
|
||||
// When formatting numbers you will often want to
|
||||
// control the width and precision of the resulting
|
||||
// figure. To specify the width of an integer, use a
|
||||
// number after the `%` in the verb. By default the
|
||||
// result will be right-justified and padded with
|
||||
// spaces.
|
||||
fmt.Printf("|%6d|%6d|\n", 12, 345)
|
||||
|
||||
// You can also specify the width of printed floats,
|
||||
// though usually you'll also want to restrict the
|
||||
// decimal precision at the same time with the
|
||||
// width.precision syntax.
|
||||
fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
|
||||
// You can also specify the width of printed floats,
|
||||
// though usually you'll also want to restrict the
|
||||
// decimal precision at the same time with the
|
||||
// width.precision syntax.
|
||||
fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45)
|
||||
|
||||
// To left-justify, use the `-` flag.
|
||||
fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
|
||||
// To left-justify, use the `-` flag.
|
||||
fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45)
|
||||
|
||||
// You may also want to control width when formatting
|
||||
// strings, especially to ensure that they align in
|
||||
// table-like output. For basic right-justified width.
|
||||
fmt.Printf("|%6s|%6s|\n", "foo", "b")
|
||||
// You may also want to control width when formatting
|
||||
// strings, especially to ensure that they align in
|
||||
// table-like output. For basic right-justified width.
|
||||
fmt.Printf("|%6s|%6s|\n", "foo", "b")
|
||||
|
||||
// To left-justify use the `-` flag as with numbers.
|
||||
fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
|
||||
// To left-justify use the `-` flag as with numbers.
|
||||
fmt.Printf("|%-6s|%-6s|\n", "foo", "b")
|
||||
|
||||
// So far we've seen `Printf`, which prints the
|
||||
// formatted string to `os.Stdout`. `Sprintf` formats
|
||||
// and returns a string without printing it anywhere.
|
||||
s := fmt.Sprintf("a %s", "string")
|
||||
fmt.Println(s)
|
||||
// So far we've seen `Printf`, which prints the
|
||||
// formatted string to `os.Stdout`. `Sprintf` formats
|
||||
// and returns a string without printing it anywhere.
|
||||
s := fmt.Sprintf("a %s", "string")
|
||||
fmt.Println(s)
|
||||
|
||||
// You can format+print to `io.Writers` other than
|
||||
// `os.Stdout` using `Fprintf`.
|
||||
fmt.Fprintf(os.Stderr, "an %s\n", "error")
|
||||
// You can format+print to `io.Writers` other than
|
||||
// `os.Stdout` using `Fprintf`.
|
||||
fmt.Fprintf(os.Stderr, "an %s\n", "error")
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
5f39ae6d8f26d59a688a9a9d7d13a5c1d0f7a08b
|
||||
JJAAFGxHVq
|
||||
CkBQ3CFpHQ9
|
||||
|
@ -13,32 +13,32 @@ var p = fmt.Println
|
||||
|
||||
func main() {
|
||||
|
||||
// Here's a sample of the functions available in
|
||||
// `strings`. Since these are functions from the
|
||||
// package, not methods on the string object itself,
|
||||
// we need pass the string in question as the first
|
||||
// argument to the function. You can find more
|
||||
// functions in the [`strings`](http://golang.org/pkg/strings/)
|
||||
// package docs.
|
||||
p("Contains: ", s.Contains("test", "es"))
|
||||
p("Count: ", s.Count("test", "t"))
|
||||
p("HasPrefix: ", s.HasPrefix("test", "te"))
|
||||
p("HasSuffix: ", s.HasSuffix("test", "st"))
|
||||
p("Index: ", s.Index("test", "e"))
|
||||
p("Join: ", s.Join([]string{"a", "b"}, "-"))
|
||||
p("Repeat: ", s.Repeat("a", 5))
|
||||
p("Replace: ", s.Replace("foo", "o", "0", -1))
|
||||
p("Replace: ", s.Replace("foo", "o", "0", 1))
|
||||
p("Split: ", s.Split("a-b-c-d-e", "-"))
|
||||
p("ToLower: ", s.ToLower("TEST"))
|
||||
p("ToUpper: ", s.ToUpper("test"))
|
||||
p()
|
||||
// Here's a sample of the functions available in
|
||||
// `strings`. Since these are functions from the
|
||||
// package, not methods on the string object itself,
|
||||
// we need pass the string in question as the first
|
||||
// argument to the function. You can find more
|
||||
// functions in the [`strings`](http://golang.org/pkg/strings/)
|
||||
// package docs.
|
||||
p("Contains: ", s.Contains("test", "es"))
|
||||
p("Count: ", s.Count("test", "t"))
|
||||
p("HasPrefix: ", s.HasPrefix("test", "te"))
|
||||
p("HasSuffix: ", s.HasSuffix("test", "st"))
|
||||
p("Index: ", s.Index("test", "e"))
|
||||
p("Join: ", s.Join([]string{"a", "b"}, "-"))
|
||||
p("Repeat: ", s.Repeat("a", 5))
|
||||
p("Replace: ", s.Replace("foo", "o", "0", -1))
|
||||
p("Replace: ", s.Replace("foo", "o", "0", 1))
|
||||
p("Split: ", s.Split("a-b-c-d-e", "-"))
|
||||
p("ToLower: ", s.ToLower("TEST"))
|
||||
p("ToUpper: ", s.ToUpper("test"))
|
||||
p()
|
||||
|
||||
// Not part of `strings`, but worth mentioning here, are
|
||||
// the mechanisms for getting the length of a string in
|
||||
// bytes and getting a byte by index.
|
||||
p("Len: ", len("hello"))
|
||||
p("Char:", "hello"[1])
|
||||
// Not part of `strings`, but worth mentioning here, are
|
||||
// the mechanisms for getting the length of a string in
|
||||
// bytes and getting a byte by index.
|
||||
p("Len: ", len("hello"))
|
||||
p("Char:", "hello"[1])
|
||||
}
|
||||
|
||||
// Note that `len` and indexing above work at the byte level.
|
||||
|
@ -1,2 +1,2 @@
|
||||
17aa523bbd606fa0b624fae44b89812d46330755
|
||||
Lf5_Zbg6or
|
||||
Vn4D3y4_711
|
||||
|
@ -8,34 +8,34 @@ import "fmt"
|
||||
|
||||
// This `person` struct type has `name` and `age` fields.
|
||||
type person struct {
|
||||
name string
|
||||
age int
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// This syntax creates a new struct.
|
||||
fmt.Println(person{"Bob", 20})
|
||||
// This syntax creates a new struct.
|
||||
fmt.Println(person{"Bob", 20})
|
||||
|
||||
// You can name the fields when initializing a struct.
|
||||
fmt.Println(person{name: "Alice", age: 30})
|
||||
// You can name the fields when initializing a struct.
|
||||
fmt.Println(person{name: "Alice", age: 30})
|
||||
|
||||
// Omitted fields will be zero-valued.
|
||||
fmt.Println(person{name: "Fred"})
|
||||
// Omitted fields will be zero-valued.
|
||||
fmt.Println(person{name: "Fred"})
|
||||
|
||||
// An `&` prefix yields a pointer to the struct.
|
||||
fmt.Println(&person{name: "Ann", age: 40})
|
||||
// An `&` prefix yields a pointer to the struct.
|
||||
fmt.Println(&person{name: "Ann", age: 40})
|
||||
|
||||
// Access struct fields with a dot.
|
||||
s := person{name: "Sean", age: 50}
|
||||
fmt.Println(s.name)
|
||||
// Access struct fields with a dot.
|
||||
s := person{name: "Sean", age: 50}
|
||||
fmt.Println(s.name)
|
||||
|
||||
// You can also use dots with struct pointers - the
|
||||
// pointers are automatically dereferenced.
|
||||
sp := &s
|
||||
fmt.Println(sp.age)
|
||||
// You can also use dots with struct pointers - the
|
||||
// pointers are automatically dereferenced.
|
||||
sp := &s
|
||||
fmt.Println(sp.age)
|
||||
|
||||
// Structs are mutable.
|
||||
sp.age = 51
|
||||
fmt.Println(sp.age)
|
||||
// Structs are mutable.
|
||||
sp.age = 51
|
||||
fmt.Println(sp.age)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
49cad39331ee5e9fb8d8dad99d3aff7f18a4e6d0
|
||||
OMCP5KFC10
|
||||
XMZpGsF4sWM
|
||||
|
@ -8,54 +8,54 @@ import "time"
|
||||
|
||||
func main() {
|
||||
|
||||
// Here's a basic `switch`.
|
||||
i := 2
|
||||
fmt.Print("Write ", i, " as ")
|
||||
switch i {
|
||||
case 1:
|
||||
fmt.Println("one")
|
||||
case 2:
|
||||
fmt.Println("two")
|
||||
case 3:
|
||||
fmt.Println("three")
|
||||
}
|
||||
// Here's a basic `switch`.
|
||||
i := 2
|
||||
fmt.Print("Write ", i, " as ")
|
||||
switch i {
|
||||
case 1:
|
||||
fmt.Println("one")
|
||||
case 2:
|
||||
fmt.Println("two")
|
||||
case 3:
|
||||
fmt.Println("three")
|
||||
}
|
||||
|
||||
// You can use commas to separate multiple expressions
|
||||
// in the same `case` statement. We use the optional
|
||||
// `default` case in this example as well.
|
||||
switch time.Now().Weekday() {
|
||||
case time.Saturday, time.Sunday:
|
||||
fmt.Println("It's the weekend")
|
||||
default:
|
||||
fmt.Println("It's a weekday")
|
||||
}
|
||||
// You can use commas to separate multiple expressions
|
||||
// in the same `case` statement. We use the optional
|
||||
// `default` case in this example as well.
|
||||
switch time.Now().Weekday() {
|
||||
case time.Saturday, time.Sunday:
|
||||
fmt.Println("It's the weekend")
|
||||
default:
|
||||
fmt.Println("It's a weekday")
|
||||
}
|
||||
|
||||
// `switch` without an expression is an alternate way
|
||||
// to express if/else logic. Here we also show how the
|
||||
// `case` expressions can be non-constants.
|
||||
t := time.Now()
|
||||
switch {
|
||||
case t.Hour() < 12:
|
||||
fmt.Println("It's before noon")
|
||||
default:
|
||||
fmt.Println("It's after noon")
|
||||
}
|
||||
// `switch` without an expression is an alternate way
|
||||
// to express if/else logic. Here we also show how the
|
||||
// `case` expressions can be non-constants.
|
||||
t := time.Now()
|
||||
switch {
|
||||
case t.Hour() < 12:
|
||||
fmt.Println("It's before noon")
|
||||
default:
|
||||
fmt.Println("It's after noon")
|
||||
}
|
||||
|
||||
// A type `switch` compares types instead of values. You
|
||||
// can use this to discover the type of an interface
|
||||
// value. In this example, the variable `t` will have the
|
||||
// type corresponding to its clause.
|
||||
whatAmI := func(i interface{}) {
|
||||
switch t := i.(type) {
|
||||
case bool:
|
||||
fmt.Println("I'm a bool")
|
||||
case int:
|
||||
fmt.Println("I'm an int")
|
||||
default:
|
||||
fmt.Printf("Don't know type %T\n", t)
|
||||
}
|
||||
}
|
||||
whatAmI(true)
|
||||
whatAmI(1)
|
||||
whatAmI("hey")
|
||||
// A type `switch` compares types instead of values. You
|
||||
// can use this to discover the type of an interface
|
||||
// value. In this example, the variable `t` will have the
|
||||
// type corresponding to its clause.
|
||||
whatAmI := func(i interface{}) {
|
||||
switch t := i.(type) {
|
||||
case bool:
|
||||
fmt.Println("I'm a bool")
|
||||
case int:
|
||||
fmt.Println("I'm an int")
|
||||
default:
|
||||
fmt.Printf("Don't know type %T\n", t)
|
||||
}
|
||||
}
|
||||
whatAmI(true)
|
||||
whatAmI(1)
|
||||
whatAmI("hey")
|
||||
}
|
||||
|
@ -11,21 +11,21 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Tickers use a similar mechanism to timers: a
|
||||
// channel that is sent values. Here we'll use the
|
||||
// `range` builtin on the channel to iterate over
|
||||
// the values as they arrive every 500ms.
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
go func() {
|
||||
for t := range ticker.C {
|
||||
fmt.Println("Tick at", t)
|
||||
}
|
||||
}()
|
||||
// Tickers use a similar mechanism to timers: a
|
||||
// channel that is sent values. Here we'll use the
|
||||
// `range` builtin on the channel to iterate over
|
||||
// the values as they arrive every 500ms.
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
go func() {
|
||||
for t := range ticker.C {
|
||||
fmt.Println("Tick at", t)
|
||||
}
|
||||
}()
|
||||
|
||||
// Tickers can be stopped like timers. Once a ticker
|
||||
// is stopped it won't receive any more values on its
|
||||
// channel. We'll stop ours after 1600ms.
|
||||
time.Sleep(1600 * time.Millisecond)
|
||||
ticker.Stop()
|
||||
fmt.Println("Ticker stopped")
|
||||
// Tickers can be stopped like timers. Once a ticker
|
||||
// is stopped it won't receive any more values on its
|
||||
// channel. We'll stop ours after 1600ms.
|
||||
time.Sleep(1600 * time.Millisecond)
|
||||
ticker.Stop()
|
||||
fmt.Println("Ticker stopped")
|
||||
}
|
||||
|
@ -7,44 +7,44 @@ import "fmt"
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
p := fmt.Println
|
||||
p := fmt.Println
|
||||
|
||||
// Here's a basic example of formatting a time
|
||||
// according to RFC3339, using the corresponding layout
|
||||
// constant.
|
||||
t := time.Now()
|
||||
p(t.Format(time.RFC3339))
|
||||
// Here's a basic example of formatting a time
|
||||
// according to RFC3339, using the corresponding layout
|
||||
// constant.
|
||||
t := time.Now()
|
||||
p(t.Format(time.RFC3339))
|
||||
|
||||
// Time parsing uses the same layout values as `Format`.
|
||||
t1, e := time.Parse(
|
||||
time.RFC3339,
|
||||
"2012-11-01T22:08:41+00:00")
|
||||
p(t1)
|
||||
// Time parsing uses the same layout values as `Format`.
|
||||
t1, e := time.Parse(
|
||||
time.RFC3339,
|
||||
"2012-11-01T22:08:41+00:00")
|
||||
p(t1)
|
||||
|
||||
// `Format` and `Parse` use example-based layouts. Usually
|
||||
// you'll use a constant from `time` for these layouts, but
|
||||
// you can also supply custom layouts. Layouts must use the
|
||||
// reference time `Mon Jan 2 15:04:05 MST 2006` to show the
|
||||
// pattern with which to format/parse a given time/string.
|
||||
// The example time must be exactly as shown: the year 2006,
|
||||
// 15 for the hour, Monday for the day of the week, etc.
|
||||
p(t.Format("3:04PM"))
|
||||
p(t.Format("Mon Jan _2 15:04:05 2006"))
|
||||
p(t.Format("2006-01-02T15:04:05.999999-07:00"))
|
||||
form := "3 04 PM"
|
||||
t2, e := time.Parse(form, "8 41 PM")
|
||||
p(t2)
|
||||
// `Format` and `Parse` use example-based layouts. Usually
|
||||
// you'll use a constant from `time` for these layouts, but
|
||||
// you can also supply custom layouts. Layouts must use the
|
||||
// reference time `Mon Jan 2 15:04:05 MST 2006` to show the
|
||||
// pattern with which to format/parse a given time/string.
|
||||
// The example time must be exactly as shown: the year 2006,
|
||||
// 15 for the hour, Monday for the day of the week, etc.
|
||||
p(t.Format("3:04PM"))
|
||||
p(t.Format("Mon Jan _2 15:04:05 2006"))
|
||||
p(t.Format("2006-01-02T15:04:05.999999-07:00"))
|
||||
form := "3 04 PM"
|
||||
t2, e := time.Parse(form, "8 41 PM")
|
||||
p(t2)
|
||||
|
||||
// For purely numeric representations you can also
|
||||
// use standard string formatting with the extracted
|
||||
// components of the time value.
|
||||
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
|
||||
t.Year(), t.Month(), t.Day(),
|
||||
t.Hour(), t.Minute(), t.Second())
|
||||
// For purely numeric representations you can also
|
||||
// use standard string formatting with the extracted
|
||||
// components of the time value.
|
||||
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
|
||||
t.Year(), t.Month(), t.Day(),
|
||||
t.Hour(), t.Minute(), t.Second())
|
||||
|
||||
// `Parse` will return an error on malformed input
|
||||
// explaining the parsing problem.
|
||||
ansic := "Mon Jan _2 15:04:05 2006"
|
||||
_, e = time.Parse(ansic, "8:41PM")
|
||||
p(e)
|
||||
// `Parse` will return an error on malformed input
|
||||
// explaining the parsing problem.
|
||||
ansic := "Mon Jan _2 15:04:05 2006"
|
||||
_, e = time.Parse(ansic, "8:41PM")
|
||||
p(e)
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
1f9962260f5c92efe57db0b96099b3dd06c90333
|
||||
BFw556nWcM
|
||||
nHAisH6amZG
|
||||
|
@ -7,55 +7,55 @@ import "fmt"
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
p := fmt.Println
|
||||
p := fmt.Println
|
||||
|
||||
// We'll start by getting the current time.
|
||||
now := time.Now()
|
||||
p(now)
|
||||
// We'll start by getting the current time.
|
||||
now := time.Now()
|
||||
p(now)
|
||||
|
||||
// You can build a `time` struct by providing the
|
||||
// year, month, day, etc. Times are always associated
|
||||
// with a `Location`, i.e. time zone.
|
||||
then := time.Date(
|
||||
2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||
p(then)
|
||||
// You can build a `time` struct by providing the
|
||||
// year, month, day, etc. Times are always associated
|
||||
// with a `Location`, i.e. time zone.
|
||||
then := time.Date(
|
||||
2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||
p(then)
|
||||
|
||||
// You can extract the various components of the time
|
||||
// value as expected.
|
||||
p(then.Year())
|
||||
p(then.Month())
|
||||
p(then.Day())
|
||||
p(then.Hour())
|
||||
p(then.Minute())
|
||||
p(then.Second())
|
||||
p(then.Nanosecond())
|
||||
p(then.Location())
|
||||
// You can extract the various components of the time
|
||||
// value as expected.
|
||||
p(then.Year())
|
||||
p(then.Month())
|
||||
p(then.Day())
|
||||
p(then.Hour())
|
||||
p(then.Minute())
|
||||
p(then.Second())
|
||||
p(then.Nanosecond())
|
||||
p(then.Location())
|
||||
|
||||
// The Monday-Sunday `Weekday` is also available.
|
||||
p(then.Weekday())
|
||||
// The Monday-Sunday `Weekday` is also available.
|
||||
p(then.Weekday())
|
||||
|
||||
// These methods compare two times, testing if the
|
||||
// first occurs before, after, or at the same time
|
||||
// as the second, respectively.
|
||||
p(then.Before(now))
|
||||
p(then.After(now))
|
||||
p(then.Equal(now))
|
||||
// These methods compare two times, testing if the
|
||||
// first occurs before, after, or at the same time
|
||||
// as the second, respectively.
|
||||
p(then.Before(now))
|
||||
p(then.After(now))
|
||||
p(then.Equal(now))
|
||||
|
||||
// The `Sub` methods returns a `Duration` representing
|
||||
// the interval between two times.
|
||||
diff := now.Sub(then)
|
||||
p(diff)
|
||||
// The `Sub` methods returns a `Duration` representing
|
||||
// the interval between two times.
|
||||
diff := now.Sub(then)
|
||||
p(diff)
|
||||
|
||||
// We can compute the length of the duration in
|
||||
// various units.
|
||||
p(diff.Hours())
|
||||
p(diff.Minutes())
|
||||
p(diff.Seconds())
|
||||
p(diff.Nanoseconds())
|
||||
// We can compute the length of the duration in
|
||||
// various units.
|
||||
p(diff.Hours())
|
||||
p(diff.Minutes())
|
||||
p(diff.Seconds())
|
||||
p(diff.Nanoseconds())
|
||||
|
||||
// You can use `Add` to advance a time by a given
|
||||
// duration, or with a `-` to move backwards by a
|
||||
// duration.
|
||||
p(then.Add(diff))
|
||||
p(then.Add(-diff))
|
||||
// You can use `Add` to advance a time by a given
|
||||
// duration, or with a `-` to move backwards by a
|
||||
// duration.
|
||||
p(then.Add(diff))
|
||||
p(then.Add(-diff))
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
b6308f1fea7665e89a28f54aac6cb49b95685eb5
|
||||
TTYPzggHg0
|
||||
PZMCzzaJURJ
|
||||
|
@ -10,39 +10,39 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// For our example, suppose we're executing an external
|
||||
// call that returns its result on a channel `c1`
|
||||
// after 2s.
|
||||
c1 := make(chan string, 1)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c1 <- "result 1"
|
||||
}()
|
||||
// For our example, suppose we're executing an external
|
||||
// call that returns its result on a channel `c1`
|
||||
// after 2s.
|
||||
c1 := make(chan string, 1)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c1 <- "result 1"
|
||||
}()
|
||||
|
||||
// Here's the `select` implementing a timeout.
|
||||
// `res := <-c1` awaits the result and `<-Time.After`
|
||||
// awaits a value to be sent after the timeout of
|
||||
// 1s. Since `select` proceeds with the first
|
||||
// receive that's ready, we'll take the timeout case
|
||||
// if the operation takes more than the allowed 1s.
|
||||
select {
|
||||
case res := <-c1:
|
||||
fmt.Println(res)
|
||||
case <-time.After(1 * time.Second):
|
||||
fmt.Println("timeout 1")
|
||||
}
|
||||
// Here's the `select` implementing a timeout.
|
||||
// `res := <-c1` awaits the result and `<-Time.After`
|
||||
// awaits a value to be sent after the timeout of
|
||||
// 1s. Since `select` proceeds with the first
|
||||
// receive that's ready, we'll take the timeout case
|
||||
// if the operation takes more than the allowed 1s.
|
||||
select {
|
||||
case res := <-c1:
|
||||
fmt.Println(res)
|
||||
case <-time.After(1 * time.Second):
|
||||
fmt.Println("timeout 1")
|
||||
}
|
||||
|
||||
// If we allow a longer timeout of 3s, then the receive
|
||||
// from `c2` will succeed and we'll print the result.
|
||||
c2 := make(chan string, 1)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c2 <- "result 2"
|
||||
}()
|
||||
select {
|
||||
case res := <-c2:
|
||||
fmt.Println(res)
|
||||
case <-time.After(3 * time.Second):
|
||||
fmt.Println("timeout 2")
|
||||
}
|
||||
// If we allow a longer timeout of 3s, then the receive
|
||||
// from `c2` will succeed and we'll print the result.
|
||||
c2 := make(chan string, 1)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
c2 <- "result 2"
|
||||
}()
|
||||
select {
|
||||
case res := <-c2:
|
||||
fmt.Println(res)
|
||||
case <-time.After(3 * time.Second):
|
||||
fmt.Println("timeout 2")
|
||||
}
|
||||
}
|
||||
|
@ -11,29 +11,29 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Timers represent a single event in the future. You
|
||||
// tell the timer how long you want to wait, and it
|
||||
// provides a channel that will be notified at that
|
||||
// time. This timer will wait 2 seconds.
|
||||
timer1 := time.NewTimer(2 * time.Second)
|
||||
// Timers represent a single event in the future. You
|
||||
// tell the timer how long you want to wait, and it
|
||||
// provides a channel that will be notified at that
|
||||
// time. This timer will wait 2 seconds.
|
||||
timer1 := time.NewTimer(2 * time.Second)
|
||||
|
||||
// The `<-timer1.C` blocks on the timer's channel `C`
|
||||
// until it sends a value indicating that the timer
|
||||
// expired.
|
||||
<-timer1.C
|
||||
fmt.Println("Timer 1 expired")
|
||||
// The `<-timer1.C` blocks on the timer's channel `C`
|
||||
// until it sends a value indicating that the timer
|
||||
// expired.
|
||||
<-timer1.C
|
||||
fmt.Println("Timer 1 expired")
|
||||
|
||||
// If you just wanted to wait, you could have used
|
||||
// `time.Sleep`. One reason a timer may be useful is
|
||||
// that you can cancel the timer before it expires.
|
||||
// Here's an example of that.
|
||||
timer2 := time.NewTimer(time.Second)
|
||||
go func() {
|
||||
<-timer2.C
|
||||
fmt.Println("Timer 2 expired")
|
||||
}()
|
||||
stop2 := timer2.Stop()
|
||||
if stop2 {
|
||||
fmt.Println("Timer 2 stopped")
|
||||
}
|
||||
// If you just wanted to wait, you could have used
|
||||
// `time.Sleep`. One reason a timer may be useful is
|
||||
// that you can cancel the timer before it expires.
|
||||
// Here's an example of that.
|
||||
timer2 := time.NewTimer(time.Second)
|
||||
go func() {
|
||||
<-timer2.C
|
||||
fmt.Println("Timer 2 expired")
|
||||
}()
|
||||
stop2 := timer2.Stop()
|
||||
if stop2 {
|
||||
fmt.Println("Timer 2 stopped")
|
||||
}
|
||||
}
|
||||
|
@ -9,47 +9,47 @@ import "net/url"
|
||||
|
||||
func main() {
|
||||
|
||||
// We'll parse this example URL, which includes a
|
||||
// scheme, authentication info, host, port, path,
|
||||
// query params, and query fragment.
|
||||
s := "postgres://user:pass@host.com:5432/path?k=v#f"
|
||||
// We'll parse this example URL, which includes a
|
||||
// scheme, authentication info, host, port, path,
|
||||
// query params, and query fragment.
|
||||
s := "postgres://user:pass@host.com:5432/path?k=v#f"
|
||||
|
||||
// Parse the URL and ensure there are no errors.
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Parse the URL and ensure there are no errors.
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Accessing the scheme is straightforward.
|
||||
fmt.Println(u.Scheme)
|
||||
// Accessing the scheme is straightforward.
|
||||
fmt.Println(u.Scheme)
|
||||
|
||||
// `User` contains all authentication info; call
|
||||
// `Username` and `Password` on this for individual
|
||||
// values.
|
||||
fmt.Println(u.User)
|
||||
fmt.Println(u.User.Username())
|
||||
p, _ := u.User.Password()
|
||||
fmt.Println(p)
|
||||
// `User` contains all authentication info; call
|
||||
// `Username` and `Password` on this for individual
|
||||
// values.
|
||||
fmt.Println(u.User)
|
||||
fmt.Println(u.User.Username())
|
||||
p, _ := u.User.Password()
|
||||
fmt.Println(p)
|
||||
|
||||
// The `Host` contains both the hostname and the port,
|
||||
// if present. Use `SplitHostPort` to extract them.
|
||||
fmt.Println(u.Host)
|
||||
host, port, _ := net.SplitHostPort(u.Host)
|
||||
fmt.Println(host)
|
||||
fmt.Println(port)
|
||||
// The `Host` contains both the hostname and the port,
|
||||
// if present. Use `SplitHostPort` to extract them.
|
||||
fmt.Println(u.Host)
|
||||
host, port, _ := net.SplitHostPort(u.Host)
|
||||
fmt.Println(host)
|
||||
fmt.Println(port)
|
||||
|
||||
// Here we extract the `path` and the fragment after
|
||||
// the `#`.
|
||||
fmt.Println(u.Path)
|
||||
fmt.Println(u.Fragment)
|
||||
// Here we extract the `path` and the fragment after
|
||||
// the `#`.
|
||||
fmt.Println(u.Path)
|
||||
fmt.Println(u.Fragment)
|
||||
|
||||
// To get query params in a string of `k=v` format,
|
||||
// use `RawQuery`. You can also parse query params
|
||||
// into a map. The parsed query param maps are from
|
||||
// strings to slices of strings, so index into `[0]`
|
||||
// if you only want the first value.
|
||||
fmt.Println(u.RawQuery)
|
||||
m, _ := url.ParseQuery(u.RawQuery)
|
||||
fmt.Println(m)
|
||||
fmt.Println(m["k"][0])
|
||||
// To get query params in a string of `k=v` format,
|
||||
// use `RawQuery`. You can also parse query params
|
||||
// into a map. The parsed query param maps are from
|
||||
// strings to slices of strings, so index into `[0]`
|
||||
// if you only want the first value.
|
||||
fmt.Println(u.RawQuery)
|
||||
m, _ := url.ParseQuery(u.RawQuery)
|
||||
fmt.Println(m)
|
||||
fmt.Println(m["k"][0])
|
||||
}
|
||||
|
@ -8,15 +8,15 @@ import "fmt"
|
||||
|
||||
func main() {
|
||||
|
||||
// Strings, which can be added together with `+`.
|
||||
fmt.Println("go" + "lang")
|
||||
// Strings, which can be added together with `+`.
|
||||
fmt.Println("go" + "lang")
|
||||
|
||||
// Integers and floats.
|
||||
fmt.Println("1+1 =", 1+1)
|
||||
fmt.Println("7.0/3.0 =", 7.0/3.0)
|
||||
// Integers and floats.
|
||||
fmt.Println("1+1 =", 1+1)
|
||||
fmt.Println("7.0/3.0 =", 7.0/3.0)
|
||||
|
||||
// Booleans, with boolean operators as you'd expect.
|
||||
fmt.Println(true && false)
|
||||
fmt.Println(true || false)
|
||||
fmt.Println(!true)
|
||||
// Booleans, with boolean operators as you'd expect.
|
||||
fmt.Println(true && false)
|
||||
fmt.Println(true || false)
|
||||
fmt.Println(!true)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user