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