mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 19:54:21 +08:00
deploy: 06a1bdf735
This commit is contained in:
48
vendor/gopl.io/ch5/defer1/defer.go
generated
vendored
Normal file
48
vendor/gopl.io/ch5/defer1/defer.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 150.
|
||||
|
||||
// Defer1 demonstrates a deferred call being invoked during a panic.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
//!+f
|
||||
func main() {
|
||||
f(3)
|
||||
}
|
||||
|
||||
func f(x int) {
|
||||
fmt.Printf("f(%d)\n", x+0/x) // panics if x == 0
|
||||
defer fmt.Printf("defer %d\n", x)
|
||||
f(x - 1)
|
||||
}
|
||||
|
||||
//!-f
|
||||
|
||||
/*
|
||||
//!+stdout
|
||||
f(3)
|
||||
f(2)
|
||||
f(1)
|
||||
defer 1
|
||||
defer 2
|
||||
defer 3
|
||||
//!-stdout
|
||||
|
||||
//!+stderr
|
||||
panic: runtime error: integer divide by zero
|
||||
main.f(0)
|
||||
src/gopl.io/ch5/defer1/defer.go:14
|
||||
main.f(1)
|
||||
src/gopl.io/ch5/defer1/defer.go:16
|
||||
main.f(2)
|
||||
src/gopl.io/ch5/defer1/defer.go:16
|
||||
|
||||
main.f(3)
|
||||
src/gopl.io/ch5/defer1/defer.go:16
|
||||
main.main()
|
||||
src/gopl.io/ch5/defer1/defer.go:10
|
||||
//!-stderr
|
||||
*/
|
||||
51
vendor/gopl.io/ch5/defer2/defer.go
generated
vendored
Normal file
51
vendor/gopl.io/ch5/defer2/defer.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 151.
|
||||
|
||||
// Defer2 demonstrates a deferred call to runtime.Stack during a panic.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
defer printStack()
|
||||
f(3)
|
||||
}
|
||||
|
||||
func printStack() {
|
||||
var buf [4096]byte
|
||||
n := runtime.Stack(buf[:], false)
|
||||
os.Stdout.Write(buf[:n])
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func f(x int) {
|
||||
fmt.Printf("f(%d)\n", x+0/x) // panics if x == 0
|
||||
defer fmt.Printf("defer %d\n", x)
|
||||
f(x - 1)
|
||||
}
|
||||
|
||||
/*
|
||||
//!+printstack
|
||||
goroutine 1 [running]:
|
||||
main.printStack()
|
||||
src/gopl.io/ch5/defer2/defer.go:20
|
||||
main.f(0)
|
||||
src/gopl.io/ch5/defer2/defer.go:27
|
||||
main.f(1)
|
||||
src/gopl.io/ch5/defer2/defer.go:29
|
||||
main.f(2)
|
||||
src/gopl.io/ch5/defer2/defer.go:29
|
||||
main.f(3)
|
||||
src/gopl.io/ch5/defer2/defer.go:29
|
||||
main.main()
|
||||
src/gopl.io/ch5/defer2/defer.go:15
|
||||
//!-printstack
|
||||
*/
|
||||
54
vendor/gopl.io/ch5/fetch/main.go
generated
vendored
Normal file
54
vendor/gopl.io/ch5/fetch/main.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 148.
|
||||
|
||||
// Fetch saves the contents of a URL into a local file.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
//!+
|
||||
// Fetch downloads the URL and returns the
|
||||
// name and length of the local file.
|
||||
func fetch(url string) (filename string, n int64, err error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
local := path.Base(resp.Request.URL.Path)
|
||||
if local == "/" {
|
||||
local = "index.html"
|
||||
}
|
||||
f, err := os.Create(local)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
n, err = io.Copy(f, resp.Body)
|
||||
// Close file, but prefer error from Copy, if any.
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
return local, n, err
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
for _, url := range os.Args[1:] {
|
||||
local, n, err := fetch(url)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "fetch %s: %v\n", url, err)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s => %s (%d bytes).\n", url, local, n)
|
||||
}
|
||||
}
|
||||
76
vendor/gopl.io/ch5/findlinks1/main.go
generated
vendored
Normal file
76
vendor/gopl.io/ch5/findlinks1/main.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 122.
|
||||
//!+main
|
||||
|
||||
// Findlinks1 prints the links in an HTML document read from standard input.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
func main() {
|
||||
doc, err := html.Parse(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "findlinks1: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
for _, link := range visit(nil, doc) {
|
||||
fmt.Println(link)
|
||||
}
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
//!+visit
|
||||
// visit appends to links each link found in n and returns the result.
|
||||
func visit(links []string, n *html.Node) []string {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key == "href" {
|
||||
links = append(links, a.Val)
|
||||
}
|
||||
}
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
links = visit(links, c)
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
//!-visit
|
||||
|
||||
/*
|
||||
//!+html
|
||||
package html
|
||||
|
||||
type Node struct {
|
||||
Type NodeType
|
||||
Data string
|
||||
Attr []Attribute
|
||||
FirstChild, NextSibling *Node
|
||||
}
|
||||
|
||||
type NodeType int32
|
||||
|
||||
const (
|
||||
ErrorNode NodeType = iota
|
||||
TextNode
|
||||
DocumentNode
|
||||
ElementNode
|
||||
CommentNode
|
||||
DoctypeNode
|
||||
)
|
||||
|
||||
type Attribute struct {
|
||||
Key, Val string
|
||||
}
|
||||
|
||||
func Parse(r io.Reader) (*Node, error)
|
||||
//!-html
|
||||
*/
|
||||
69
vendor/gopl.io/ch5/findlinks2/main.go
generated
vendored
Normal file
69
vendor/gopl.io/ch5/findlinks2/main.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 125.
|
||||
|
||||
// Findlinks2 does an HTTP GET on each URL, parses the
|
||||
// result as HTML, and prints the links within it.
|
||||
//
|
||||
// Usage:
|
||||
// findlinks url ...
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// visit appends to links each link found in n, and returns the result.
|
||||
func visit(links []string, n *html.Node) []string {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key == "href" {
|
||||
links = append(links, a.Val)
|
||||
}
|
||||
}
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
links = visit(links, c)
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
for _, url := range os.Args[1:] {
|
||||
links, err := findLinks(url)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "findlinks2: %v\n", err)
|
||||
continue
|
||||
}
|
||||
for _, link := range links {
|
||||
fmt.Println(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findLinks performs an HTTP GET request for url, parses the
|
||||
// response as HTML, and extracts and returns the links.
|
||||
func findLinks(url string) ([]string, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("getting %s: %s", url, resp.Status)
|
||||
}
|
||||
doc, err := html.Parse(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s as HTML: %v", url, err)
|
||||
}
|
||||
return visit(nil, doc), nil
|
||||
}
|
||||
|
||||
//!-
|
||||
56
vendor/gopl.io/ch5/findlinks3/findlinks.go
generated
vendored
Normal file
56
vendor/gopl.io/ch5/findlinks3/findlinks.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 139.
|
||||
|
||||
// Findlinks3 crawls the web, starting with the URLs on the command line.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gopl.io/ch5/links"
|
||||
)
|
||||
|
||||
//!+breadthFirst
|
||||
// breadthFirst calls f for each item in the worklist.
|
||||
// Any items returned by f are added to the worklist.
|
||||
// f is called at most once for each item.
|
||||
func breadthFirst(f func(item string) []string, worklist []string) {
|
||||
seen := make(map[string]bool)
|
||||
for len(worklist) > 0 {
|
||||
items := worklist
|
||||
worklist = nil
|
||||
for _, item := range items {
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
worklist = append(worklist, f(item)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!-breadthFirst
|
||||
|
||||
//!+crawl
|
||||
func crawl(url string) []string {
|
||||
fmt.Println(url)
|
||||
list, err := links.Extract(url)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
//!-crawl
|
||||
|
||||
//!+main
|
||||
func main() {
|
||||
// Crawl the web breadth-first,
|
||||
// starting from the command-line arguments.
|
||||
breadthFirst(crawl, os.Args[1:])
|
||||
}
|
||||
|
||||
//!-main
|
||||
67
vendor/gopl.io/ch5/links/links.go
generated
vendored
Normal file
67
vendor/gopl.io/ch5/links/links.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 138.
|
||||
//!+Extract
|
||||
|
||||
// Package links provides a link-extraction function.
|
||||
package links
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// Extract makes an HTTP GET request to the specified URL, parses
|
||||
// the response as HTML, and returns the links in the HTML document.
|
||||
func Extract(url string) ([]string, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
resp.Body.Close()
|
||||
return nil, fmt.Errorf("getting %s: %s", url, resp.Status)
|
||||
}
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing %s as HTML: %v", url, err)
|
||||
}
|
||||
|
||||
var links []string
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key != "href" {
|
||||
continue
|
||||
}
|
||||
link, err := resp.Request.URL.Parse(a.Val)
|
||||
if err != nil {
|
||||
continue // ignore bad URLs
|
||||
}
|
||||
links = append(links, link.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
forEachNode(doc, visitNode, nil)
|
||||
return links, nil
|
||||
}
|
||||
|
||||
//!-Extract
|
||||
|
||||
// Copied from gopl.io/ch5/outline2.
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
36
vendor/gopl.io/ch5/outline/main.go
generated
vendored
Normal file
36
vendor/gopl.io/ch5/outline/main.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 123.
|
||||
|
||||
// Outline prints the outline of an HTML document tree.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
//!+
|
||||
func main() {
|
||||
doc, err := html.Parse(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "outline: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
outline(nil, doc)
|
||||
}
|
||||
|
||||
func outline(stack []string, n *html.Node) {
|
||||
if n.Type == html.ElementNode {
|
||||
stack = append(stack, n.Data) // push tag
|
||||
fmt.Println(stack)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
outline(stack, c)
|
||||
}
|
||||
}
|
||||
|
||||
//!-
|
||||
80
vendor/gopl.io/ch5/outline2/outline.go
generated
vendored
Normal file
80
vendor/gopl.io/ch5/outline2/outline.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 133.
|
||||
|
||||
// Outline prints the outline of an HTML document tree.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for _, url := range os.Args[1:] {
|
||||
outline(url)
|
||||
}
|
||||
}
|
||||
|
||||
func outline(url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//!+call
|
||||
forEachNode(doc, startElement, endElement)
|
||||
//!-call
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//!+forEachNode
|
||||
// forEachNode calls the functions pre(x) and post(x) for each node
|
||||
// x in the tree rooted at n. Both functions are optional.
|
||||
// pre is called before the children are visited (preorder) and
|
||||
// post is called after (postorder).
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
//!-forEachNode
|
||||
|
||||
//!+startend
|
||||
var depth int
|
||||
|
||||
func startElement(n *html.Node) {
|
||||
if n.Type == html.ElementNode {
|
||||
fmt.Printf("%*s<%s>\n", depth*2, "", n.Data)
|
||||
depth++
|
||||
}
|
||||
}
|
||||
|
||||
func endElement(n *html.Node) {
|
||||
if n.Type == html.ElementNode {
|
||||
depth--
|
||||
fmt.Printf("%*s</%s>\n", depth*2, "", n.Data)
|
||||
}
|
||||
}
|
||||
|
||||
//!-startend
|
||||
30
vendor/gopl.io/ch5/squares/main.go
generated
vendored
Normal file
30
vendor/gopl.io/ch5/squares/main.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 135.
|
||||
|
||||
// The squares program demonstrates a function value with state.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
//!+
|
||||
// squares returns a function that returns
|
||||
// the next square number each time it is called.
|
||||
func squares() func() int {
|
||||
var x int
|
||||
return func() int {
|
||||
x++
|
||||
return x * x
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := squares()
|
||||
fmt.Println(f()) // "1"
|
||||
fmt.Println(f()) // "4"
|
||||
fmt.Println(f()) // "9"
|
||||
fmt.Println(f()) // "16"
|
||||
}
|
||||
|
||||
//!-
|
||||
33
vendor/gopl.io/ch5/sum/main.go
generated
vendored
Normal file
33
vendor/gopl.io/ch5/sum/main.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 142.
|
||||
|
||||
// The sum program demonstrates a variadic function.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
//!+
|
||||
func sum(vals ...int) int {
|
||||
total := 0
|
||||
for _, val := range vals {
|
||||
total += val
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
//!+main
|
||||
fmt.Println(sum()) // "0"
|
||||
fmt.Println(sum(3)) // "3"
|
||||
fmt.Println(sum(1, 2, 3, 4)) // "10"
|
||||
//!-main
|
||||
|
||||
//!+slice
|
||||
values := []int{1, 2, 3, 4}
|
||||
fmt.Println(sum(values...)) // "10"
|
||||
//!-slice
|
||||
}
|
||||
82
vendor/gopl.io/ch5/title1/title.go
generated
vendored
Normal file
82
vendor/gopl.io/ch5/title1/title.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 144.
|
||||
|
||||
// Title1 prints the title of an HTML document specified by a URL.
|
||||
package main
|
||||
|
||||
/*
|
||||
//!+output
|
||||
$ go build gopl.io/ch5/title1
|
||||
$ ./title1 http://gopl.io
|
||||
The Go Programming Language
|
||||
$ ./title1 https://golang.org/doc/effective_go.html
|
||||
Effective Go - The Go Programming Language
|
||||
$ ./title1 https://golang.org/doc/gopher/frontpage.png
|
||||
title: https://golang.org/doc/gopher/frontpage.png
|
||||
has type image/png, not text/html
|
||||
//!-output
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// Copied from gopl.io/ch5/outline2.
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
//!+
|
||||
func title(url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check Content-Type is HTML (e.g., "text/html; charset=utf-8").
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "text/html" && !strings.HasPrefix(ct, "text/html;") {
|
||||
resp.Body.Close()
|
||||
return fmt.Errorf("%s has type %s, not text/html", url, ct)
|
||||
}
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing %s as HTML: %v", url, err)
|
||||
}
|
||||
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "title" &&
|
||||
n.FirstChild != nil {
|
||||
fmt.Println(n.FirstChild.Data)
|
||||
}
|
||||
}
|
||||
forEachNode(doc, visitNode, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
for _, arg := range os.Args[1:] {
|
||||
if err := title(arg); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "title: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
72
vendor/gopl.io/ch5/title2/title.go
generated
vendored
Normal file
72
vendor/gopl.io/ch5/title2/title.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 145.
|
||||
|
||||
// Title2 prints the title of an HTML document specified by a URL.
|
||||
// It uses defer to simplify closing the response body stream.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// Copied from gopl.io/ch5/outline2.
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
//!+
|
||||
func title(url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "text/html" && !strings.HasPrefix(ct, "text/html;") {
|
||||
return fmt.Errorf("%s has type %s, not text/html", url, ct)
|
||||
}
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing %s as HTML: %v", url, err)
|
||||
}
|
||||
|
||||
// ...print doc's title element...
|
||||
//!-
|
||||
visitNode := func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "title" &&
|
||||
n.FirstChild != nil {
|
||||
fmt.Println(n.FirstChild.Data)
|
||||
}
|
||||
}
|
||||
forEachNode(doc, visitNode, nil)
|
||||
//!+
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
for _, arg := range os.Args[1:] {
|
||||
if err := title(arg); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "title: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
99
vendor/gopl.io/ch5/title3/title.go
generated
vendored
Normal file
99
vendor/gopl.io/ch5/title3/title.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 153.
|
||||
|
||||
// Title3 prints the title of an HTML document specified by a URL.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// Copied from gopl.io/ch5/outline2.
|
||||
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
|
||||
if pre != nil {
|
||||
pre(n)
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
forEachNode(c, pre, post)
|
||||
}
|
||||
if post != nil {
|
||||
post(n)
|
||||
}
|
||||
}
|
||||
|
||||
//!+
|
||||
// soleTitle returns the text of the first non-empty title element
|
||||
// in doc, and an error if there was not exactly one.
|
||||
func soleTitle(doc *html.Node) (title string, err error) {
|
||||
type bailout struct{}
|
||||
|
||||
defer func() {
|
||||
switch p := recover(); p {
|
||||
case nil:
|
||||
// no panic
|
||||
case bailout{}:
|
||||
// "expected" panic
|
||||
err = fmt.Errorf("multiple title elements")
|
||||
default:
|
||||
panic(p) // unexpected panic; carry on panicking
|
||||
}
|
||||
}()
|
||||
|
||||
// Bail out of recursion if we find more than one non-empty title.
|
||||
forEachNode(doc, func(n *html.Node) {
|
||||
if n.Type == html.ElementNode && n.Data == "title" &&
|
||||
n.FirstChild != nil {
|
||||
if title != "" {
|
||||
panic(bailout{}) // multiple title elements
|
||||
}
|
||||
title = n.FirstChild.Data
|
||||
}
|
||||
}, nil)
|
||||
if title == "" {
|
||||
return "", fmt.Errorf("no title element")
|
||||
}
|
||||
return title, nil
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func title(url string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check Content-Type is HTML (e.g., "text/html; charset=utf-8").
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "text/html" && !strings.HasPrefix(ct, "text/html;") {
|
||||
resp.Body.Close()
|
||||
return fmt.Errorf("%s has type %s, not text/html", url, ct)
|
||||
}
|
||||
|
||||
doc, err := html.Parse(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing %s as HTML: %v", url, err)
|
||||
}
|
||||
title, err := soleTitle(doc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(title)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
for _, arg := range os.Args[1:] {
|
||||
if err := title(arg); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "title: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
69
vendor/gopl.io/ch5/toposort/main.go
generated
vendored
Normal file
69
vendor/gopl.io/ch5/toposort/main.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 136.
|
||||
|
||||
// The toposort program prints the nodes of a DAG in topological order.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
//!+table
|
||||
// prereqs maps computer science courses to their prerequisites.
|
||||
var prereqs = map[string][]string{
|
||||
"algorithms": {"data structures"},
|
||||
"calculus": {"linear algebra"},
|
||||
|
||||
"compilers": {
|
||||
"data structures",
|
||||
"formal languages",
|
||||
"computer organization",
|
||||
},
|
||||
|
||||
"data structures": {"discrete math"},
|
||||
"databases": {"data structures"},
|
||||
"discrete math": {"intro to programming"},
|
||||
"formal languages": {"discrete math"},
|
||||
"networks": {"operating systems"},
|
||||
"operating systems": {"data structures", "computer organization"},
|
||||
"programming languages": {"data structures", "computer organization"},
|
||||
}
|
||||
|
||||
//!-table
|
||||
|
||||
//!+main
|
||||
func main() {
|
||||
for i, course := range topoSort(prereqs) {
|
||||
fmt.Printf("%d:\t%s\n", i+1, course)
|
||||
}
|
||||
}
|
||||
|
||||
func topoSort(m map[string][]string) []string {
|
||||
var order []string
|
||||
seen := make(map[string]bool)
|
||||
var visitAll func(items []string)
|
||||
|
||||
visitAll = func(items []string) {
|
||||
for _, item := range items {
|
||||
if !seen[item] {
|
||||
seen[item] = true
|
||||
visitAll(m[item])
|
||||
order = append(order, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for key := range m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
visitAll(keys)
|
||||
return order
|
||||
}
|
||||
|
||||
//!-main
|
||||
40
vendor/gopl.io/ch5/trace/main.go
generated
vendored
Normal file
40
vendor/gopl.io/ch5/trace/main.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 146.
|
||||
|
||||
// The trace program uses defer to add entry/exit diagnostics to a function.
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+main
|
||||
func bigSlowOperation() {
|
||||
defer trace("bigSlowOperation")() // don't forget the extra parentheses
|
||||
// ...lots of work...
|
||||
time.Sleep(10 * time.Second) // simulate slow operation by sleeping
|
||||
}
|
||||
|
||||
func trace(msg string) func() {
|
||||
start := time.Now()
|
||||
log.Printf("enter %s", msg)
|
||||
return func() { log.Printf("exit %s (%s)", msg, time.Since(start)) }
|
||||
}
|
||||
|
||||
//!-main
|
||||
|
||||
func main() {
|
||||
bigSlowOperation()
|
||||
}
|
||||
|
||||
/*
|
||||
!+output
|
||||
$ go build gopl.io/ch5/trace
|
||||
$ ./trace
|
||||
2015/11/18 09:53:26 enter bigSlowOperation
|
||||
2015/11/18 09:53:36 exit bigSlowOperation (10.000589217s)
|
||||
!-output
|
||||
*/
|
||||
50
vendor/gopl.io/ch5/wait/wait.go
generated
vendored
Normal file
50
vendor/gopl.io/ch5/wait/wait.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
|
||||
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
// See page 130.
|
||||
|
||||
// The wait program waits for an HTTP server to start responding.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
//!+
|
||||
// WaitForServer attempts to contact the server of a URL.
|
||||
// It tries for one minute using exponential back-off.
|
||||
// It reports an error if all attempts fail.
|
||||
func WaitForServer(url string) error {
|
||||
const timeout = 1 * time.Minute
|
||||
deadline := time.Now().Add(timeout)
|
||||
for tries := 0; time.Now().Before(deadline); tries++ {
|
||||
_, err := http.Head(url)
|
||||
if err == nil {
|
||||
return nil // success
|
||||
}
|
||||
log.Printf("server not responding (%s); retrying...", err)
|
||||
time.Sleep(time.Second << uint(tries)) // exponential back-off
|
||||
}
|
||||
return fmt.Errorf("server %s failed to respond after %s", url, timeout)
|
||||
}
|
||||
|
||||
//!-
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "usage: wait url\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
url := os.Args[1]
|
||||
//!+main
|
||||
// (In function main.)
|
||||
if err := WaitForServer(url); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Site is down: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
//!-main
|
||||
}
|
||||
Reference in New Issue
Block a user