Merge branch 'master' into clipboard

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

2
.env
View File

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

3
.gitattributes vendored Normal file
View File

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

3
.gitignore vendored
View File

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

1
.godir
View File

@ -1 +0,0 @@
gobyexample

18
.travis.yml Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ func main() {
// We'll use an unsigned integer to represent our
// (always-positive) counter.
var ops uint64 = 0
var ops uint64
// To simulate concurrent updates, we'll start 50
// goroutines that each increment the counter about

View File

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

View File

@ -17,7 +17,7 @@ func main() {
// Go supports both standard and URL-compatible
// base64. Here's how to encode using the standard
// encoder. The encoder requires a `[]byte` so we
// cast our `string` to that type.
// convert our `string` to that type.
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
// We can use channels to synchronize execution
// across goroutines. Here's an example of using a
// blocking receive to wait for a goroutine to finish.
// When waiting for multiple goroutines to finish,
// you may prefer to use a [WaitGroup](waitgroups).
package main

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ import "fmt"
func intSeq() func() int {
i := 0
return func() int {
i += 1
i++
return i
}
}

View File

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

View File

@ -21,7 +21,7 @@ package main
import "strings"
import "fmt"
// Returns the first index of the target string `t`, or
// Index returns the first index of the target string `t`, or
// -1 if no match is found.
func Index(vs []string, t string) int {
for i, v := range vs {
@ -32,13 +32,13 @@ func Index(vs []string, t string) int {
return -1
}
// Returns `true` if the target string t is in the
// Include returns `true` if the target string t is in the
// slice.
func Include(vs []string, t string) bool {
return Index(vs, t) >= 0
}
// Returns `true` if one of the strings in the slice
// Any returns `true` if one of the strings in the slice
// satisfies the predicate `f`.
func Any(vs []string, f func(string) bool) bool {
for _, v := range vs {
@ -49,7 +49,7 @@ func Any(vs []string, f func(string) bool) bool {
return false
}
// Returns `true` if all of the strings in the slice
// All returns `true` if all of the strings in the slice
// satisfy the predicate `f`.
func All(vs []string, f func(string) bool) bool {
for _, v := range vs {
@ -60,7 +60,7 @@ func All(vs []string, f func(string) bool) bool {
return true
}
// Returns a new slice containing all strings in the
// Filter returns a new slice containing all strings in the
// slice that satisfy the predicate `f`.
func Filter(vs []string, f func(string) bool) []string {
vsf := make([]string, 0)
@ -72,7 +72,7 @@ func Filter(vs []string, f func(string) bool) []string {
return vsf
}
// Returns a new slice containing the results of applying
// Map returns a new slice containing the results of applying
// the function `f` to each string in the original slice.
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))

View File

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

View File

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

View File

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

View File

@ -54,6 +54,3 @@ $ ./command-line-flags -wat
flag provided but not defined: -wat
Usage of ./command-line-flags:
...
# Next we'll look at environment variables, another common
# way to parameterize programs.

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ func main() {
fmt.Println(d)
// A numeric constant has no type until it's given
// one, such as by an explicit cast.
// one, such as by an explicit conversion.
fmt.Println(int64(d))
// A number can be given a type by using it in a

View File

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

View File

@ -40,5 +40,11 @@ func writeFile(f *os.File) {
func closeFile(f *os.File) {
fmt.Println("closing")
f.Close()
err := f.Close()
// It's important to check for errors when closing a
// file, even in a deferred function.
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,7 +23,7 @@ func f1(arg int) (int, error) {
}
// A nil value in the error position indicates that
// A `nil` value in the error position indicates that
// there was no error.
return arg + 3, nil
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,9 +30,8 @@ func main() {
// Our two function calls are running asynchronously in
// separate goroutines now, so execution falls through
// to here. This `Scanln` code requires we press a key
// to here. This `Scanln` requires we press a key
// before the program exits.
var input string
fmt.Scanln(&input)
fmt.Scanln()
fmt.Println("done")
}

View File

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

View File

@ -1,6 +1,6 @@
# When we run this program, we see the output of the
# blocking call first, then the interleaved output of the
# two gouroutines. This interleaving reflects the
# two goroutines. This interleaving reflects the
# goroutines being run concurrently by the Go runtime.
$ go run goroutines.go
direct : 0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,11 +10,11 @@ import "os"
// We'll use these two structs to demonstrate encoding and
// decoding of custom types below.
type Response1 struct {
type response1 struct {
Page int
Fruits []string
}
type Response2 struct {
type response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"`
}
@ -50,7 +50,7 @@ func main() {
// custom data types. It will only include exported
// fields in the encoded output and will by default
// use those names as the JSON keys.
res1D := &Response1{
res1D := &response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res1B, _ := json.Marshal(res1D)
@ -58,9 +58,9 @@ func main() {
// You can use tags on struct field declarations
// to customize the encoded JSON key names. Check the
// definition of `Response2` above to see an example
// definition of `response2` above to see an example
// of such tags.
res2D := &Response2{
res2D := &response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"}}
res2B, _ := json.Marshal(res2D)
@ -85,14 +85,14 @@ func main() {
fmt.Println(dat)
// In order to use the values in the decoded map,
// we'll need to cast them to their appropriate type.
// For example here we cast the value in `num` to
// we'll need to convert them to their appropriate type.
// For example here we convert the value in `num` to
// the expected `float64` type.
num := dat["num"].(float64)
fmt.Println(num)
// Accessing nested data requires a series of
// casts.
// conversions.
strs := dat["strs"].([]interface{})
str1 := strs[0].(string)
fmt.Println(str1)
@ -103,7 +103,7 @@ func main() {
// need for type assertions when accessing the decoded
// data.
str := `{"page": 1, "fruits": ["apple", "peach"]}`
res := Response2{}
res := response2{}
json.Unmarshal([]byte(str), &res)
fmt.Println(res)
fmt.Println(res.Fruits[0])

View File

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

View File

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

View File

@ -16,7 +16,7 @@ func main() {
m["k1"] = 7
m["k2"] = 13
// Printing a map with e.g. `Println` will show all of
// Printing a map with e.g. `fmt.Println` will show all of
// its key/value pairs.
fmt.Println("map:", m)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
// In the previous example we saw how to manage simple
// counter state using [atomic operations](atomic-counters).
// For more complex state we can use a _[mutex](http://en.wikipedia.org/wiki/Mutual_exclusion)_
// For more complex state we can use a <em>[mutex](http://en.wikipedia.org/wiki/Mutual_exclusion)</em>
// to safely access data across multiple goroutines.
package main
@ -23,8 +23,8 @@ func main() {
// We'll keep track of how many read and write
// operations we do.
var readOps uint64 = 0
var writeOps uint64 = 0
var readOps uint64
var writeOps uint64
// Here we start 100 goroutines to execute repeated
// reads against the state, once per millisecond in

View File

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

View File

@ -22,7 +22,10 @@ func main() {
fmt.Println("no message received")
}
// A non-blocking send works similarly.
// A non-blocking send works similarly. Here `msg`
// cannot be sent to the `messages` channel, because
// the channel has no buffer and there is no receiver.
// Therefore the `default` case is selected.
msg := "hi"
select {
case messages <- msg:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
// _[Rate limiting](http://en.wikipedia.org/wiki/Rate_limiting)_
// <em>[Rate limiting](http://en.wikipedia.org/wiki/Rate_limiting)</em>
// is an important mechanism for controlling resource
// utilization and maintaining quality of service. Go
// elegantly supports rate limiting with goroutines,
@ -24,7 +24,7 @@ func main() {
// This `limiter` channel will receive a value
// every 200 milliseconds. This is the regulator in
// our rate limiting scheme.
limiter := time.Tick(time.Millisecond * 200)
limiter := time.Tick(200 * time.Millisecond)
// By blocking on a receive from the `limiter` channel
// before serving each request, we limit ourselves to
@ -49,7 +49,7 @@ func main() {
// Every 200 milliseconds we'll try to add a new
// value to `burstyLimiter`, up to its limit of 3.
go func() {
for t := range time.Tick(time.Millisecond * 200) {
for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t
}
}()

View File

@ -1,2 +1,2 @@
d74aebb12f618f22ec776eb5b4de92985104c197
e7yzIk97-p
edad78bf3b36ddc9bec30b344b8a72be4de90f3b
l4uDE-RCDpa

View File

@ -40,7 +40,7 @@ func main() {
b1 := make([]byte, 5)
n1, err := f.Read(b1)
check(err)
fmt.Printf("%d bytes: %s\n", n1, string(b1))
fmt.Printf("%d bytes: %s\n", n1, string(b1[:n1]))
// You can also `Seek` to a known location in the file
// and `Read` from there.
@ -49,7 +49,8 @@ func main() {
b2 := make([]byte, 2)
n2, err := f.Read(b2)
check(err)
fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2))
fmt.Printf("%d bytes @ %d: ", n2, o2)
fmt.Printf("%v\n", string(b2[:n2]))
// The `io` package provides some functions that may
// be helpful for file reading. For example, reads
@ -80,5 +81,4 @@ func main() {
// be scheduled immediately after `Open`ing with
// `defer`).
f.Close()
}

View File

@ -1,2 +1,2 @@
2aa7a2e248065cebfa6f8eece3234b5ffa710273
2kEKXq-kUV
463a6f2999a023887af6b23c8f79f24978eb8115
cocJ6kBH_iZ

View File

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

View File

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

View File

@ -17,11 +17,11 @@ func main() {
// of time, to simulate e.g. blocking RPC operations
// executing in concurrent goroutines.
go func() {
time.Sleep(time.Second * 1)
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(time.Second * 2)
time.Sleep(2 * time.Second)
c2 <- "two"
}()

View File

@ -1,2 +1,2 @@
72503557ab54ef765eeba153fe8a3446541dfc5f
Vco7d8Lmhn
8d743edffd7de6bf7bccdf4437f45672b6adc75e
ZdSOPe1Gj13

View File

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

View File

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

View File

@ -30,7 +30,7 @@ func main() {
// arrays. One is the builtin `append`, which
// returns a slice containing one or more new values.
// Note that we need to accept a return value from
// append as we may get a new slice value.
// `append` as we may get a new slice value.
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println("apd:", s)

View File

@ -1,2 +1,2 @@
d900c3b1cf2bd96591f7ad7ce7fd9e592ec31139
dPQErsP6Yc
c6fa1627841f199dbf901f88580cb97eb92c5530
Z3_U32sn8RF

View File

@ -10,10 +10,10 @@ import "sort"
import "fmt"
// In order to sort by a custom function in Go, we need a
// corresponding type. Here we've created a `ByLength`
// corresponding type. Here we've created a `byLength`
// type that is just an alias for the builtin `[]string`
// type.
type ByLength []string
type byLength []string
// We implement `sort.Interface` - `Len`, `Less`, and
// `Swap` - on our type so we can use the `sort` package's
@ -22,22 +22,22 @@ type ByLength []string
// hold the actual custom sorting logic. In our case we
// want to sort in order of increasing string length, so
// we use `len(s[i])` and `len(s[j])` here.
func (s ByLength) Len() int {
func (s byLength) Len() int {
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]
}
func (s ByLength) Less(i, j int) bool {
func (s byLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
// With all of this in place, we can now implement our
// custom sort by casting the original `fruits` slice to
// `ByLength`, and then use `sort.Sort` on that typed
// custom sort by converting the original `fruits` slice
// to `byLength`, and then use `sort.Sort` on that typed
// slice.
func main() {
fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(ByLength(fruits))
sort.Sort(byLength(fruits))
fmt.Println(fruits)
}

View File

@ -1,2 +1,2 @@
cec0da0bd98abd7f66fcd38122e4405f757161bc
N6GbEgBffd
6a04058b564d5741815e523f97f240ee6563cb15
y3kuCwIFRYK

View File

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

View File

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

View File

@ -37,14 +37,14 @@ type writeOp struct {
func main() {
// As before we'll count how many operations we perform.
var readOps uint64 = 0
var writeOps uint64 = 0
var readOps uint64
var writeOps uint64
// The `reads` and `writes` channels will be used by
// other goroutines to issue read and write requests,
// respectively.
reads := make(chan *readOp)
writes := make(chan *writeOp)
reads := make(chan readOp)
writes := make(chan writeOp)
// Here is the goroutine that owns the `state`, which
// is a map as in the previous example but now private
@ -76,7 +76,7 @@ func main() {
for r := 0; r < 100; r++ {
go func() {
for {
read := &readOp{
read := readOp{
key: rand.Intn(5),
resp: make(chan int)}
reads <- read
@ -92,7 +92,7 @@ func main() {
for w := 0; w < 10; w++ {
go func() {
for {
write := &writeOp{
write := writeOp{
key: rand.Intn(5),
val: rand.Intn(100),
resp: make(chan bool)}

View File

@ -1,2 +1,2 @@
c306add52c0752f0b3099eb669364fc4bdb74be1
P4SrrlosMp
956afe7524b492b2e85f8320c70f180c448a764a
saQTLpdIgp2

View File

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

View File

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

View File

@ -12,6 +12,15 @@ type person struct {
age int
}
// NewPerson constructs a new person struct with the given name
func NewPerson(name string) *person {
// You can safely return a pointer to local variable
// as a local variable will survive the scope of the function.
p := person{name: name}
p.age = 42
return &p
}
func main() {
// This syntax creates a new struct.
@ -26,6 +35,9 @@ func main() {
// An `&` prefix yields a pointer to the struct.
fmt.Println(&person{name: "Ann", age: 40})
// It's idiomatic to encapsulate new struct creation in constructor functions
fmt.Println(NewPerson("Jon"))
// Access struct fields with a dot.
s := person{name: "Sean", age: 50}
fmt.Println(s.name)

View File

@ -1,2 +1,2 @@
49cad39331ee5e9fb8d8dad99d3aff7f18a4e6d0
OMCP5KFC10
c5caaf1eefaf084d688afb70d2ee5884a4983182
00Yiw6xuICq

View File

@ -6,3 +6,4 @@ $ go run structs.go
Sean
50
51
&{Jon 42}

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