I finished the official Grammar teaching of A Tour of Go in these two days, with A lot of Excercise. Hope to be useful to you, if other people have also written, and think I write wrong, ask for advice! ❤ ️

Exercise: Loops and Functions

The title

  • Give me a numberx, we use loop and function to find the square rootz, i.e.,Z squared = x
  • Tour.golang.org/flowcontrol…

answer

package main

import (
	"fmt"
	"math"
)

func Sqrt(x float64) float64 {
	z := x/2
	for i:= 0; math.Abs(z*z - x) > 0.0000000001; i++ {
		z -= (z*z - x) / (2*z)
		fmt.Println(i, "z:", z, "z^2 -x:", z*z - x)
	}
	return z
}

func main(a) {
	fmt.Println(Sqrt(1000))}Copy the code
  1. z := x/2The hint is set to 1.
  2. Math.Abs(z* z-x) > 0.0000000001Using the logic of optimal solution is to give a tolerance0.0000000001That’s what we figured out using the formulaZ squaredxThe difference is small enough that we assume the estimatedzIt’s an approximate accurate value.

Exercise: Slices

The title

  • Write aPicFunction to generate one[][]uint8Array of Array. Its size is determined by the parameter(dx, dy int)Decision, this one hasdyEach of these arrays has a length ofdxThe array. And the relative positionpic[y][x]Is the Bluescale (only blue) value for this image in the format ofuint8.
  • Tour.golang.org/moretypes/1…

answer

package main

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

func Pic(dx, dy int)[] []uint8 {
	pic := make([] []uint8, dy)
	for i := range pic {
		pic[i] = make([]uint8, dx)
		for j := range pic[i] {
			pic[i][j] = uint8(i*j + j*j)
		}
	}
	return pic
}

func main(a) {
	pic.Show(Pic)
}
Copy the code

  1. pic := make([][]uint8, dy)I’m going to create an array of lengthdyThe contents of each element in an array are an array[]uint8
  2. pic[i] = make([]uint8, dx)At the first point in the arrayiLet’s create another one[]uint8Array of lengthdx
  3. pic[i][j] = uint8(i*j + j*j)Denotes that in the Calculation formula of the Bluesacle we designed,pic[i][j]The value of the position is zerouint8(i*j + j*j)(Here you can arbitrarily change a few, you can see a lot of different effects!)

Exercise: Maps

The title

  • Implement a functionWordCount, it can reply to onemapThis contains the number of occurrences of the word word in the input string.
  • For example: “I love you you you you”, returnmap[string]int{"I":1, "love":1, "you":3}
  • Tour.golang.org/moretypes/2…

answer

package main

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	m := make(map[string]int)
	words := strings.Fields(s)
	for _, word := range words {
		m[word] = m[word] + 1
	}
	return m
}

func main(a) {
	wc.Test(WordCount)
}
Copy the code
  1. Strings.Files(s) this function automatically splits a string into an array, each of which contains a word
  2. To establishmapAnd then every time in the arraywordIf it appears, it increases by 1

Exercise: Fibonacci closure

The title

  • To implement afibonacciFunction to return a function
  • This function will continuously output the Fibonacci sequence
  • Tour.golang.org/moretypes/2…

answer

package main

import "fmt"

// fibonacci is a function that returns
// a function that returns an int.
func fibonacci(a) func(a) int {
	a, b := 0.1
	return func(a) int {
		c := a
		a, b = b, a+b
		return c
	}
}

func main(a) {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
Copy the code
  1. A closure, also called a closure, means that a variable that needs to be used in a function is defined outside the function itself
  2. In the abovefunc fibonacci() func() int, returns a functionfunc() intAnd this function returns one at a timeint
  3. infibonacci()The variableabDefined in a functionfibonacci()Is returned by this functionreturn func() int { ... }The function is referred to, that is, in the function that is returnedabBoth variables are always stored in memory, and their values are always changing
  4. f := fibonacci()ffibonacci()The function that returns, in the initial case, at this pointa, b := 0, 1
  5. For the first timef()Call as an example:
    • c := a:cThe assignment foraNamely 0
    • a, b = b, a+b:aThe assignment forbWhich is 1,bThe assignment fora+bWhich is 1
    • return cReturns 0, which is the Fibonacci numberThe first value
  6. The second timef()Call, notice at this pointaIs 1,bIs 1:
    • c := a:cThe assignment foraWhich is 1
    • a, b = b, a+b:aThe assignment forbWhich is 1,bThe assignment fora+bThat is 2
    • return cReturns 1, which is the Fibonacci sequenceThe second value
  7. And so onfThe function is called 10 times and outputs the first 10 values of the Fibonacci sequence

Exercise: Stringers

The title

  • fortype IPAddr [4]byteAdd Stringer Interface function to output string, i.eIPAddr{1, 2, 3, 4}The print is2.
  • tour.golang.org/methods/18

answer

package main

import (
	"fmt"
	"strings"
	"strconv"
)

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String(a) string {
	s := make([]string.len(ip))
	for i, val := range ip {
		s[i] = strconv.Itoa(int(val))
	}
	return fmt.Sprintf(strings.Join(s, "."))}func main(a) {
	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)
	}
}
Copy the code
  1. Strconv. Itoa int to String
  2. IPAddrIt’s a size 4[]byte, we generate one[4]stringAn array ofsEach element is a bit in the IP address, and we usestrconv.Itoa(int(val))Convert it to a string
  3. strings.Join(s, ".")Use string arrays"."together
  4. In this wayfmt.Printf("%v: %v\n", name, ip), totype IPAddrCall it by defaultStringer interfaceThe definition ofString()Function to output

Exercise: Errors

The title

  • Exercise: Loops and FunctionssqrtFunction, added when the argument is a negative numbertype ErrNegativeSqrt float64And by definitionfunc (e ErrNegativeSqrt) Error() stringSo that makes it zeroerror
  • tour.golang.org/methods/20

answer

package main

import (
	"fmt"
	"math"
)

type ErrNegativeSqrt float64

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

func Sqrt(x float64) (float64, error) {
	if (x > 0) {
		z:= x/2
		for i:= 0; math.Abs(z*z - x) > 0.0000000001; i++ {
			z -= (z*z - x) / (2*z)
			fmt.Println(i, "z:", z, "z^2 -x:", z*z - x)
		}
		return z, nil
	} else {
		return 0, ErrNegativeSqrt(x)
	}
}
Copy the code
  1. errorThe type is a built-in interface that needs to be definedError() stringFunction, test oneerrorIf the type isnilIs a way to define whether a function returns an error. Such as:i, err := strconv.Atoi("42")The return value ofiRepresents the return value of the function, anderrIf it is notnilIf so, an error has occurred
  2. func (e ErrNegativeSqrt) Error() stringDefines theErrNegativeSqrtBelong toerrorError()Delta function, which is just a neat statementErrNegativeSqrtIs aerror
  3. func Sqrt(x float64) (float64, error)The function returns two values, the square root of the argument and the seconderrorWhen the latter is notnilAt the time ofPrintlnIs automatically calledError()Output the corresponding error message string.

Exercise: Readers

The title

  • To implement aReaderType to output an infinite number'A'The character of the flow
  • tour.golang.org/methods/22

answer

package main

import (
	"fmt"
	"golang.org/x/tour/reader"
)

type MyReader struct{}

type ErrEmptyBuffer []byte

func (b ErrEmptyBuffer) Error(a) string {
	return fmt.Sprintf("cannot read an empty buffer: %v", b)
}

// TODO: Add a Read([]byte) (int, error) method to MyReader.
func (reader MyReader) Read(b []byte) (int, error) {
	bLength := len(b)
	if (bLength == 0) {
		return 0, ErrEmptyBuffer(b)
	}
	for i := range b {
		b[i] = 'A'
	}
	return bLength, nil
}

func main(a) {
	reader.Validate(MyReader{})
}
Copy the code
  1. becauseMyReaderIt prints an infinite number'A', so just enter parametersb []byteIf it’s not an empty Buffer, it’s full
  2. whenbLength == 0Is the BufferbIf null, returnErrEmptyBuffer(b)error
  3. Everything that is not empty is filled'A'And returnbLength, nil

Exercise: rot13Reader

The title

  • To implement arot13ReaderType causes it to contain oneio.ReaderMake it workReadFunction, automatically based onrot13To convert the corresponding alphabetic characters.
  • tour.golang.org/methods/23

answer

package main

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

type rot13Reader struct {
	r io.Reader
}

func rot13(c byte) byte {
	switch {
	case (c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm'):
		c += 13
	case (c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z'):
		c -= 13
	}
	return c
}

func (reader *rot13Reader) Read(b []byte) (n int, err error) {
	n, err := reader.r.Read(b)
	for i := range b {
		b[i] = rot13(b[i])
	}
	return n, err
}


func main(a) {
	s := strings.NewReader("Lbh penpxrq gur pbqr!")
	r := rot13Reader{s}
	io.Copy(os.Stdout, &r)
}
Copy the code
  1. According to the firstrot13Rule implementation functionfunc rot13(c byte) byte, that is,A-MN-ZExchange, anda-mn-zThe conversion of
  2. definerot13ReaderReadFunction, which is included in the first use periodrReader to read the data, and then each piece of data passes throughrot13Convert, and eventually return the corresponding numeric result

Exercise: Images

The title

  • Optimize the image functions implemented in Exercise: Slices, one this timeimage.ImageThe image is not just a two-dimensional array of data
  • To define aImageType and define the correspondingimage.ImageInterface,
    • ColorModelusecolor.RGBAModel
    • Boundsuseimage.RectangleThe type andimage.Rect(0, 0, w, h)define
    • AtReturns the color on the pixel of the specific image, and finally usescolor.RGBA{v, v, 255, 255}define
  • tour.golang.org/methods/25

answer

package main

import (
	"golang.org/x/tour/pic"
	"image"
	"image/color"
)

type Image struct{
	W int
	H int
}

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

func (i Image) Bounds(a) image.Rectangle {
	return image.Rect(0.0, i.W, i.H)
}

func (i Image) At(x, y int)  color.Color {
	v := uint8(x*y + y*y)
	return color.RGBA{v, v, 255.255}}func main(a) {
	m := Image{200.200}
	pic.ShowImage(m)
}
Copy the code

  1. Because I’m gonna useimage.Rect.color.RGBAModel.color.RGBASo let’s introduce"image""image/color" packages
  2. You define the correlation function, and you get the result, right hereAtFunction I use the previous picture color calculation formulav := uint8(x*y + y*y)

Exercise: Equivalent Binary Trees

The title

  • The same binary tree sequence may be stored in different binary trees. For example, in the figure above, two binary trees store the sequence 1, 1, 2, 3, 5, 8, 13. defineTreeType and implement the following function to test bothTreeWhether to store the same array.
    1. implementationTreeWalkMethod, which passes in the sequence of numbers stored in the tree one by onech chan intStudent: Middle, which is equal tofunc Walk(t *tree.Tree, ch chan int)And this is done in goroutinego Walk(tree.New(1), ch). Note:tree.New(k)It randomly generates a tree of different structures, but it all stores the same arrayk.2k. .10k.
    2. implementationSameFunction and callWalkMethod to make it possible to compare twoTreeWhether to store the same array. Such as:Same(tree.New(1), tree.New(1))Should be returnedtrueBecause it’s all there1.2.10. whileSame(tree.New(1), tree.New(2))Should be returnedfalse

answer

package main

import (
	"fmt"
	"golang.org/x/tour/tree"
)

// type Tree struct {
// Left *Tree
// Value int
// Right *Tree
// }

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	ift.Left ! =nil {
		Walk(t.Left, ch)
	}
	ch <- t.Value
	ift.Right ! =nil {
		Walk(t.Right, ch)
	}
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	var v1, v2 int
	c1 := make(chan int)
	c2 := make(chan int)
	go Walk(t1, c1)
	go Walk(t2, c2)
	for i := 0; i < 10; i++ {
		v1 = <-c1
		v2 = <-c2
		ifv1 ! = v2 {return false}}return true
}

func main(a) {
	ch := make(chan int)
	go Walk(tree.New(10), ch)
	for i := 0; i < 10; i++ {
		fmt.Println(<-ch)
	}
	fmt.Println(Same(tree.New(1), tree.New(1)))}Copy the code
  1. WalkIn the method, we follow thet.Left.ch <- t.Value.t.RightPass in the data one by one in orderch
  2. SameMethod, because we know thattree.New(k)The generated tree contains 10 nodes, so we generate two Channels to store two respectivelyTreeWalkAnd then a Loop of 10 times takes out a value from it each time to compare whether the value under the corresponding sequence is the same. If there are differences, the two trees are not the same.

Exercise: Web Crawler

Ymkalasoo, we are looking for a good Go developer

The title

  • Implementation of a parallel Web Crawler, implementationCrawlFunction makes it possible to catch them in parallelURLBut don’t repeat fetching
  • fakeFetcherIs a dummy data set representing data that can be captured by the crawler under test
  • Tour.golang.org/concurrency…

answer

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 UrlChecker struct {
	urls map[string]bool
	mux sync.Mutex
}

func (c *UrlChecker) Crawled(url string) bool {
	c.mux.Lock()
	if c.urls[url] {
		defer c.mux.Unlock()
		return true
	}
	c.urls[url] = true
	defer c.mux.Unlock()
	return false
}

var uc = UrlChecker{urls: 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, ret chan string) {
	// TODO: Fetch URLs in parallel.
	// TODO: Don't fetch the same URL twice.
	// This implementation doesn't do either:
	defer close(ret)
	if depth <= 0 {
		return
	}
	if uc.Crawled(url) {
		return
	}
	body, urls, err := fetcher.Fetch(url)
	iferr ! =nil {
		fmt.Println(err)
		return
	}
	ret <- fmt.Sprintf("found: %s %q\n", url, body)
	results := make([]chan string.len(urls))
	for i, u := range urls {
		results[i] = make(chan string)
		go Crawl(u, depth- 1, fetcher, results[i])
	}
	
	for _, result := range results {
		for s := range result {
			ret <- s
		}
	}
	
	return
}

func main(a) {
	result := make(chan string)
	go Crawl("https://golang.org/".4, fetcher, result)
	for s := range result {
		fmt.Println(s)
	}
}

// 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) (stringAnd []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"And []string{
			"https://golang.org/pkg/"."https://golang.org/cmd/",}},"https://golang.org/pkg/": &fakeResult{
		"Packages"And []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"And []string{
			"https://golang.org/"."https://golang.org/pkg/",}},"https://golang.org/pkg/os/": &fakeResult{
		"Package os"And []string{
			"https://golang.org/"."https://golang.org/pkg/",,}}}Copy the code
  1. UrlCheckerIt was to test aurlHave you beenfetchYes, it contains oneurls map[string]boolStore URL fetching, andmux sync.MutexTo prevent the data from being modified repeatedly so that it doesn’t show up when fetcher is parallel, because none of the urls are thereUrlCheckerTagged fetch, and then fetch simultaneously.
  2. func (c *UrlChecker) Crawled(url string) boolTo store the state of a URL that has been fetched. During testingc.mux.Lock()If so, this section of data is blocked from being modified by other Goroutine.defer c.mux.Unlock()Mean inreturnThen perform the Mutual Exclusion lock unlocks.
  3. The statementvar uc = UrlChecker{urls: make(map[string]bool)}whenuc.Crawled(url)trueWhen, no longer grab the corresponding URL.
  4. func Crawl(url string, depth int, fetcher Fetcher, ret chan string)The last parameterret chan stringPass in a channel to store the fetch results
  5. results := make([]chan string, len(urls))For each url that needs to be captured at a deeper level, multiple channels are generated and captured one by one
  6. go Crawl(u, depth-1, fetcher, results[i])Cyclic fetch of urls
  7. Copy the code

For _, result := range results {for s := range result {ret < -s}} ‘ ‘ Complete all fetching

Final output:

not found: https://golang.org/cmd/
found: https://golang.org/ "The Go Programming Language"

found: https://golang.org/pkg/ "Packages"

found: https://golang.org/pkg/fmt/ "Package fmt"

found: https://golang.org/pkg/os/ "Package os"
Copy the code

Hard, I also learn to Go oh!