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 *.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 ## Contributing
Go by Example is now in a steady state. We are maintaining it, but are not Thanks for your interest in contributing to Go by Example!
expanding or significantly changing it any more.
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 * We're open to adding more examples to the site. They should be on things
.go or .sh source file should be sufficient for the PR. I can rebuild the used by many programmers and only require the standard library. If you're
HTML when I review the change. 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 * We're not going to change the navigation of the site, in particular adding
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
a "previous section" link or an "index" link other than the on the title a "previous section" link or an "index" link other than the on the title
text. text.

View File

@ -1,9 +1,8 @@
## Go by Example # Go by Example
Content and build toolchain for [Go by Example](https://gobyexample.com), Content and build toolchain for [Go by Example](https://gobyexample.com),
a site that teaches Go via annotated example programs. a site that teaches Go via annotated example programs.
### Overview ### Overview
The Go by Example site is built by extracting code and 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 static content system. The production site uses S3 and
CloudFront, for example. CloudFront, for example.
### Building ### 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: To build the site you'll need Go and Python installed. Run:
```console ```console
@ -34,6 +34,16 @@ To build continuously in a loop:
$ tools/build-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 ### 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: 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) * [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) * [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) * [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 ### Thanks

View File

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

View File

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

View File

@ -15,7 +15,7 @@ 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 = 0 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

View File

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

View File

@ -17,7 +17,7 @@ func main() {
// 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
// cast 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)

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
// We can use channels to synchronize execution // We can use channels to synchronize execution
// across goroutines. Here's an example of using a // across goroutines. Here's an example of using a
// blocking receive to wait for a goroutine to finish. // 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 package main

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ package main
import "strings" import "strings"
import "fmt" 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. // -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 {
@ -32,13 +32,13 @@ func Index(vs []string, t string) int {
return -1 return -1
} }
// 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
} }
// 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 {
@ -49,7 +49,7 @@ func Any(vs []string, f func(string) bool) bool {
return false 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`. // 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 {
@ -60,7 +60,7 @@ func All(vs []string, f func(string) bool) bool {
return true 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`. // 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)
@ -72,7 +72,7 @@ func Filter(vs []string, f func(string) bool) []string {
return vsf 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. // 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))

View File

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

View File

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

View File

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

View File

@ -54,6 +54,3 @@ $ ./command-line-flags -wat
flag provided but not defined: -wat flag provided but not defined: -wat
Usage of ./command-line-flags: 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) 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 cast. // 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

View File

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

View File

@ -40,5 +40,11 @@ func writeFile(f *os.File) {
func closeFile(f *os.File) { func closeFile(f *os.File) {
fmt.Println("closing") 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 fadbe9c05bb42db672316ba19adf3c2189c7b3f5
9aoHwzHcAo 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 4d0832c5a1ddd4e95474791e8802c15452358214
kfqLhpmEpw CZJ4R_uu6Uu

View File

@ -1,2 +1,2 @@
61a498229c8878a97d729cfdd215e5f3960f87ac 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. // there was no error.
return arg + 3, nil return arg + 3, nil
} }

View File

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

View File

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

View File

@ -1,2 +1,2 @@
dc0bb3eaafa045d6aa05e88aff39322a1ccf822e 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 33056d6b36f9894fb6359c9cf2ef8725bbdafa19
KNLLSX4Io_ lGYfUJwiGfi

View File

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

View File

@ -30,9 +30,8 @@ func main() {
// 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` code requires we press a key // to here. This `Scanln` requires we press a key
// before the program exits. // before the program exits.
var input string fmt.Scanln()
fmt.Scanln(&input)
fmt.Println("done") fmt.Println("done")
} }

View File

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

View File

@ -1,6 +1,6 @@
# When we run this program, we see the output of the # When we run this program, we see the output of the
# blocking call first, then the interleaved 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. # goroutines being run concurrently by the Go runtime.
$ go run goroutines.go $ go run goroutines.go
direct : 0 direct : 0

View File

@ -1,2 +1,2 @@
c98395a44701add5bf84e2f3a63e300fc1bc4bfe 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 89b78f3378e1a574ddfd0260a0404a962852eff8
g-aqMz0Ivf p6-WKTqEks4

View File

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

View File

@ -10,11 +10,11 @@ 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"`
} }
@ -50,7 +50,7 @@ func main() {
// 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)
@ -58,9 +58,9 @@ func main() {
// 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)
@ -85,14 +85,14 @@ func main() {
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 cast them to their appropriate type. // we'll need to convert them to their appropriate type.
// For example here we cast 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
// casts. // conversions.
strs := dat["strs"].([]interface{}) strs := dat["strs"].([]interface{})
str1 := strs[0].(string) str1 := strs[0].(string)
fmt.Println(str1) fmt.Println(str1)
@ -103,7 +103,7 @@ func main() {
// 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])

View File

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

View File

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

View File

@ -16,7 +16,7 @@ func main() {
m["k1"] = 7 m["k1"] = 7
m["k2"] = 13 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. // its key/value pairs.
fmt.Println("map:", m) fmt.Println("map:", m)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
// In the previous example we saw how to manage simple // In the previous example we saw how to manage simple
// counter state using [atomic operations](atomic-counters). // 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. // to safely access data across multiple goroutines.
package main package main
@ -23,8 +23,8 @@ func main() {
// 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 = 0 var readOps uint64
var writeOps uint64 = 0 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

View File

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

View File

@ -22,7 +22,10 @@ func main() {
fmt.Println("no message received") 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" msg := "hi"
select { select {
case messages <- msg: case messages <- msg:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +1,2 @@
ebe328a57f3d34708709ca99d3304af1733592d9 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 // is an important mechanism for controlling resource
// utilization and maintaining quality of service. Go // utilization and maintaining quality of service. Go
// elegantly supports rate limiting with goroutines, // elegantly supports rate limiting with goroutines,
@ -24,7 +24,7 @@ func main() {
// 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(time.Millisecond * 200) 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
@ -49,7 +49,7 @@ func main() {
// 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(time.Millisecond * 200) { for t := range time.Tick(200 * time.Millisecond) {
burstyLimiter <- t burstyLimiter <- t
} }
}() }()

View File

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

View File

@ -40,7 +40,7 @@ func main() {
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[:n1]))
// 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.
@ -49,7 +49,8 @@ func main() {
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: ", n2, o2)
fmt.Printf("%v\n", string(b2[:n2]))
// 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
@ -80,5 +81,4 @@ func main() {
// be scheduled immediately after `Open`ing with // be scheduled immediately after `Open`ing with
// `defer`). // `defer`).
f.Close() f.Close()
} }

View File

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

View File

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

View File

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

View File

@ -17,11 +17,11 @@ func main() {
// 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(time.Second * 1) time.Sleep(1 * time.Second)
c1 <- "one" c1 <- "one"
}() }()
go func() { go func() {
time.Sleep(time.Second * 2) time.Sleep(2 * time.Second)
c2 <- "two" c2 <- "two"
}() }()

View File

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

View File

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

View File

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

View File

@ -30,7 +30,7 @@ func main() {
// 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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,14 +37,14 @@ type writeOp struct {
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 = 0 var readOps uint64
var writeOps uint64 = 0 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
@ -76,7 +76,7 @@ func main() {
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
@ -92,7 +92,7 @@ func main() {
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)}

View File

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

View File

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

View File

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

View File

@ -12,6 +12,15 @@ type person struct {
age int 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() { func main() {
// This syntax creates a new struct. // This syntax creates a new struct.
@ -26,6 +35,9 @@ func main() {
// 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})
// It's idiomatic to encapsulate new struct creation in constructor functions
fmt.Println(NewPerson("Jon"))
// 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)

View File

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

View File

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

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