go指南练习题

练习:切片

https://tour.go-zh.org/moretypes/18

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"math"

	"golang.org/x/tour/pic"
)

func Pic(dx, dy int) [][]uint8 {
	pic := make([][]uint8, dy)
	for y := 0; y < dy; y++ {
		pic[y] = make([]uint8, dx)
		for x := 0; x < dx; x++ {
			pic[y][x] = uint8(x * int(math.Log(float64(y))))
		}
	}
	return pic
}

func main() {
	pic.Show(Pic)
}

终端运行结果:

yan@yanyongs-iMac tour % go run z.go
IMAGE:iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAACJklEQVR42uzX0Q3CMBBEwT3H6b/kowckftgZbQVID19usoFWx0+AAKDUTTJjVjovAE4gEAAIACo/gs8xq5z/AJxAIAAQAAgABAACAAGAAEAAIAAQAPyFSfZ5YtY5LwBOIBAACAAEAAIAAYAAQAAgABAACAAEAAIAAYAAQAAgABAACAAEAAIAAYAAQAAgABAACAAEAAIAAYAAQADwU5PsvTHrnBcAJxAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAASAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAOALk+z7xqxzXgCcQCAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAAIAAQAAgABgABAACAAEAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAAIAAQAAgABAACAAGAAEAACAAEAI0+AQAA//8Y9yPg0iquogAAAABJRU5ErkJggg==

显示成图片:

练习:映射

https://tour.go-zh.org/moretypes/23

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
	//"fmt"
	"strings"

	"golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
	m := make(map[string]int)
	//fmt.Println(m)

	a := strings.Fields(s)
	//fmt.Println(a)
	//fmt.Printf("%q\n", a)

	for _, i := range a {
		m[i]++
	}
	return m
}

func main() {
	wc.Test(WordCount)
}

练习:斐波纳契闭包

https://tour.go-zh.org/moretypes/26

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

func fibonacci() func() int {
	a, b := 0, 1
	return func() int {
		c := a
		a, b = b, a+b
		return c
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//递归版,时间复杂度为 O(2^n):
package main

import "fmt"

func fibonacci(n int) int {
	if n < 2 {
		return n
	}

	return fibonacci(n-2) + fibonacci(n-1)
}

func main() {
	for i := 0; i < 10; i++ {
		fmt.Println(fibonacci(i))
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
//通用版,时间复杂度为 O(n):
package main

import "fmt"

func fibonacci(n int) int {
	a, b := n%2, 1

	for i := 0; i < n/2; i++ {
		a += b
		b += a
	}

	return a
}

func main() {
	for i := 0; i < 10; i++ {
		fmt.Println(fibonacci(i))
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//https://tour.go-zh.org/concurrency/5
package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			//fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
}

练习:Stringer

https://tour.go-zh.org/methods/18

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import "fmt"

type IPAddr [4]byte

func (ip IPAddr) String() string {
	return fmt.Sprintf("%v.%v.%v.%v", ip[0], ip[1], ip[2], ip[3])
}

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip.String())
	}
}

练习:错误

https://tour.go-zh.org/methods/20

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
	"fmt"
	"math"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

func Sqrt(x float64) (float64, error) {
	if x < 0 {

		return x, ErrNegativeSqrt(x)

		//效果同上
		/*
			var err error
			var a ErrNegativeSqrt = ErrNegativeSqrt(x)
			err = a
			return x, err
		*/
	}
	return math.Sqrt(x), nil
}

func main() {
	fmt.Println(Sqrt(2))
	fmt.Println(Sqrt(-2))
}

练习:Reader

https://tour.go-zh.org/methods/22

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import "fmt"

//import "golang.org/x/tour/reader"

type MyReader struct{}

func (m MyReader) Read(b []byte) (int, error) {
	for i := range b {
		b[i] = 'A'
	}
	return len(b), nil
}
func main() {
	//reader.Validate(MyReader{})
	var m MyReader
	b := make([]byte, 5)
	m.Read(b)
	fmt.Println(b)
}

练习:rot13Reader

https://tour.go-zh.org/methods/23

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"io"
	"os"
	"strings"
)

type rot13Reader struct {
	r io.Reader
}

func (rot *rot13Reader) Read(b []byte) (i int, err error) {
	i, err = rot.r.Read(b)
	for i := 0; i < len(b); i++ {
		if (b[i] >= 'a' && b[i] <= 'm') || (b[i] >= 'A' && b[i] <= 'M') {
			b[i] += 13
		} else if (b[i] >= 'n' && b[i] <= 'z') || (b[i] >= 'N' && b[i] <= 'Z') {
			b[i] -= 13
		}
	}
	return
}

func main() {
	s := strings.NewReader("Lbh penpxrq gur pbqr!")
	r := rot13Reader{s}
	io.Copy(os.Stdout, &r)
}

练习:图像

https://tour.go-zh.org/methods/25

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
	"image"
	"image/color"

	"golang.org/x/tour/pic"
)

type Image struct {
	Width, Height int
}

func (img Image) ColorModel() color.Model {
	return color.RGBAModel
}

func (img Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, img.Width, img.Height)
}

func (img Image) At(x, y int) color.Color {
	return color.RGBA{uint8(x * y), 0, 255, 255}
}

func main() {
	m := Image{100, 100}
	pic.ShowImage(m)
}

终端运行结果:

yan@yanyongs-iMac tour % go run z.go 
IMAGE:iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAJjklEQVR42uybi3caxxXGJ62bpmmapmma2E5sq3pLWAJhECBeWx7LUwghhBBCgMj//ze4h7sd+l3NzO7KArcnZ3y+s+e738wK5XfuXBZivxDio7B/wv15IYT4wiqc/gPrd1Yh9F9Yv7cK0hdCfHxBzKwCtYD1ByGswmgB60shrMJoAeuPQliF0QLWV0JYhdEC1p+EsAqjBayvhbAKowWsPwthFUYLWN8IYRVGC1h/EcIqjBawvhXCKowWsP4qhFUYLWB9J4RVGC1g/U0IqzBawPpeCKswWsD6uxBWYbSA9YMQVmG0gPUPIazCaAHrRyGswoh9B/+Cvg/8kr67+Yo+Z39Nn4m+oefXb+lZ4zt6X/iezvAPxPtHIX4S4iVdfbQVtOEnIaIh9mSDNrghfkgvxJ6JkoSC9TII1ssgbQZtOArakA7aUA7a0Anxe458V1fQWa9kZ73SacOQLxUJ2nDqu+oE3d4K2jDwXZ2BD4b12hfWaziGr6hEvVMS1IHv6mshEr6rBd/Vuu9qL+il73XhszrrZz6zPFg/S70Fr2rfdzXuu5ozL1V9b7zwXb31Xf11tQN+CesXId7QVatd89IvQsTMSxnfG8vmpbbvjQPz0pSXAbDemGG9McN6Y9aOeenYvJQyLzm+L9c0L12Zl8aGfPWd9VZ21ltF27rQ05EhT5pvKZiXaualrnnp1rw0p+snwnpngPUOjuFbKpfa4uVSEUP+jga8Ns+Zb6ka8nPzLQNDPlESP1gbBlgbhs7a4DPLg7VB2pTmkQ4NedyQnxnyDZpZ2rxlyK8M+Z35JdY44Jew/qnTviGPGfK0IXcMed2Qdw350JDPwK8M1qYB1ia9zCbXnpJ4ihrylCEv6kLXsLljyAeGfKIkT4a1pYO1ZeisLdlZm+Q97YJHHevCpGFzXhdWDJvbuvDKsPlOF87pusZjuA3H0IO1TY8O24re68JtGvBqmNWFJcNPaOrCS104NPyEGXgjrB0drB0drB0drB0+szxYOzpFdGFcF2Z0oWP4sXVdeKELB7rwXheupbN2lQG/SaHXWbugQ156OtGFaV1Y1IWuLjzXhX0lGem2PUjzXFh74d4N9+AY7lK5Rx+k9xTFlORUty2vCyu6sKUkl7ptQ1045eUTYO2H66x9BdY+n1kerH1Fx7owqQtzSlLSbWsoyYVu20BJxrptz/0gfaDAOjB01iNYB/TyB6AjXnpKKMmZkji6G2tKcq7b1leSkZLMwK/9ofRQgXUoO+uA/CG9Gx5yxZXkkAb8o6SoJFUlael+VE9JhkoyURI9rIgCK6LAiiiwIgqsiNJZETiGHqyIohMlSSlJXndjRUmaStJVkoGSjJVkTtfP9HHHg/Wez6wDSiJ0XSrGy/c04B8lOSUpKUldSTpK0leSkZLMwK8M1pEC68g8szxYR7Kz3pM/oo87R1xJJcny0lE2uErSVpKekgyVZMLLTx/wx0Gddax01jGHdQzH0IN1rCjBy4yyoagkVV42lQ1dJRkoyZiXD9KEghUN6qxo0DGM6joLYUXpt4mCPvAyzcsoffmHZVnZ0OBlR9nQV5IRL6e8/JTOigXNrBiHFVOOYYzDisnOipKP0bthDJTiZY6XMZpZWNaUDee87Ckbhry8Vzas5n9YnIQe8B6sE95ZJ3AMPVgnXKe8zPLSUfa7vGzxsqvsH/Dyjpcz8Kt/N4xzWHEOK86PYZzPrCglJ3T1lAQfp4dSLIu8rPAyTjMLywte9nl5q9w+5eVnfXTwmVkerA+ys+LkE3RdKsPLAi/LvKzz8pyXPV5+oGOI5T0v53TVwEpwWAkOK8FhJTisBIeV4LASHFaCw0rAMYxTiUrzMs/LEi9rvGzz8pKXA17e8XIGfo2dleSdleSdleSdleQzKyk7K0lKSeMpB97hS1VeNnl5wcs+L295OeHlcwf8KYd1GvoYnvJjeMoH/CkcwySVS53xssjLCi8bvOzw8gr8DV8a8/JBmqfBSoXurBSHlTLPrBQf8Ck+s1L0W6ZIGWk8FXhZ5mUdfJsvXfJywMs78FO+tLJjmDYP+DTvrLR5wKf5gE/LzkqRR+V5WQLv8qUWL7vg+3zplpcT8HO6BsDKmGFlzJ2VMR/DDO+sDMDK8AGfgWOYod81I5UD74DP0MzCsgm+w5euwN/wpTH4Gfi1PzqcmR8dzpTOWsI6g5l1JjsrQz5LV09F8Gc0s5a+zpfOwV/ypQH4EV+agl/ZXznKhnvOypqfs7IAK6sM+CWsLKjAyzL4Gl9qg++C7/Ntt+Dv+dKcrk+AlQvXWTmAlTM/lOYAVg46K8cHfA5g5WRn5Whm5UAl8C74Jt92Af4K/A3fNgY/A/+JnZUHWPlwT/B5gJWHzsrrjqEHKw+dlYdjmAc5vKyCb4A/59t64AfgR+An/JbV/82/AsAqPP3jTgFgFeAYFmBmFWRnFWhmFUAV8HXwbfBd8H1++y34e/AP0nymz4ZFgFUEWEWAVYTOKsLMKsLMKsIxLHKVwdfAt8BfgL8CfwP+DvyUv8RjWA7AcgCWA7AcgOUALAdgOQDLgc5yoLMc6CwHjqEDM8uBmeXAzHJkZzmkkjQOzaylb4LvgO+BH4AfgZ+An9P1/+tbh6jyrcOjd0Mc8EtY/5KqgK+Db4Pvgu+DH4Ifg5+B/6ywSgCrBLBKAKsEsEoAqwSwSgCrRP8ZJTqGJaka+Bb4C/BX4G/A34Gfgl/lgC8DrDLAKj+ls8rQWWXorDJ0Vhk6qyw7qwxywTfBd8D3wA/Aj8BPpHmQ5lmwKk/prArAqgCsiu4YVuAYVuAYVuAYVuQxrMjOqtCjQ0WqAf4c/CX4a2mGEI7Bz8A/GVY16BhWAVY1aGZVobOquplVhZlVhZlV5TPLg1UF1cG3wXeluYLwBvwd+Kk0c7qGguUGHUM3qLNcgOXqjqELneXqBrwLM8uFmeVKWK7sLJdmlivVkqYDYQ/8APxImnsIH6RZ44CvBb0b1nTvhjXorJru3bAGM6smO6sGx7AGakpzDuEl+GtphhCOwc+k+ZUo/RYeHXBmeZ1Vp5nVpM5qE6wOvRt2CVaPjmGfYA3oGA7pCX5Ex3BMnTWhYzijzpqv+x86+cNq6GA1dLAaOlgNHawGwGpItcBfSNODcCDNLYT30swgtJ31hM6ysCwsC8vCsrAsLAvLwrKwLCwLy342/B/BupawriWsawnrWsK6lrCuAdY16VaasTRTaeZ0tZ1lj6GFZWFZWBaWhWVhWVgWloVlYVlYFpaFZWGtB9a/AwAA//+UpGahQPb9EAAAAABJRU5ErkJggg==

显示成图片:

练习:等价二叉查找树

https://tour.go-zh.org/concurrency/7

https://tour.go-zh.org/concurrency/8

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
	"fmt"

	"golang.org/x/tour/tree"
)

// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int) {
	defer close(ch) // <- closes the channel when this function returns
	var walk func(t *tree.Tree)
	walk = func(t *tree.Tree) {
		if t == nil {
			return
		}
		walk(t.Left)
		ch <- t.Value
		walk(t.Right)
	}
	walk(t)
}

// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go Walk(t1, ch1)
	go Walk(t2, ch2)

	for i := 0; i < 10; i++ {
		if <-ch1 != <-ch2 {
			return false
		}
	}
	return true
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
	fmt.Println(Same(tree.New(1), tree.New(2)))
}

参考:https://stackoverflow.com/questions/12224042/go-tour-exercise-7-binary-trees-equivalence

练习:Web 爬虫

Exercise: Web Crawler

https://tour.go-zh.org/concurrency/10

https://go.dev/tour/concurrency/10

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main

import (
	"fmt"
	"sync"
)

type Fetcher interface {
	// Fetch returns the body of URL and
	// a slice of URLs found on that page.
	Fetch(url string) (body string, urls []string, err error)
}

type History struct {
	history map[string]bool
	mux     sync.Mutex
}

func (h *History) isFetched(url string) bool {
	h.mux.Lock()
	defer h.mux.Unlock()

	_, ok := h.history[url]
	if ok {
		return ok
	} else {
		h.history[url] = true
	}
	return false
}

var history = History{history: make(map[string]bool)}

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, wg *sync.WaitGroup) {
	// TODO: Fetch URLs in parallel.
	// TODO: Don't fetch the same URL twice.
	// This implementation doesn't do either:
	defer wg.Done()
	if depth <= 0 || history.isFetched(url) {
		return
	}

	body, urls, err := fetcher.Fetch(url)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("found: %s %q\n", url, body)
	for _, u := range urls {
		wg.Add(1)
		go Crawl(u, depth-1, fetcher, wg)
	}

	return
}

func syncCrawl(url string, depth int, fetcher Fetcher) {
	var wg sync.WaitGroup
	wg.Add(1)
	go Crawl("https://golang.org/", 4, fetcher, &wg)
	wg.Wait()
}

func main() {
	syncCrawl("https://golang.org/", 4, fetcher)
	//time.Sleep(5*time.Second)
	fmt.Println("done")
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
	body string
	urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
	if res, ok := f[url]; ok {
		return res.body, res.urls, nil
	}
	return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
	"https://golang.org/": &fakeResult{
		"The Go Programming Language",
		[]string{
			"https://golang.org/pkg/",
			"https://golang.org/cmd/",
		},
	},
	"https://golang.org/pkg/": &fakeResult{
		"Packages",
		[]string{
			"https://golang.org/",
			"https://golang.org/cmd/",
			"https://golang.org/pkg/fmt/",
			"https://golang.org/pkg/os/",
		},
	},
	"https://golang.org/pkg/fmt/": &fakeResult{
		"Package fmt",
		[]string{
			"https://golang.org/",
			"https://golang.org/pkg/",
		},
	},
	"https://golang.org/pkg/os/": &fakeResult{
		"Package os",
		[]string{
			"https://golang.org/",
			"https://golang.org/pkg/",
		},
	},
}

参考:

https://tim.bai.uno/golang-exercise-web-crawler-a-tour-of-go/

https://gist.github.com/harryhare/6a4979aa7f8b90db6cbc74400d0beb49

官方文档链接

golang.org会跳转go.dev域名

https://golang.org/doc/

https://go.dev/doc/

https://golang.google.cn/doc/

https://go-zh.org/doc/

https://go.dev/tour/welcome/1

https://golang.google.cn/tour/welcome/1

https://tour.go-zh.org/welcome/1