Last active
September 14, 2017 08:06
-
-
Save tabjy/747f3de68a855ec803b9628da1cbf99e to your computer and use it in GitHub Desktop.
Go tour exercise solutions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// exercise-loops-and-functions.go -------------------------------- | |
package main | |
import ( | |
"fmt" | |
"math" | |
) | |
func newton(x float64) float64 { | |
// base case | |
if x <= 0 { return 0 } | |
z := 1.0 | |
for i := 0; i < int(x); i++ { | |
z -= (z*z - x) / (2*z) | |
} | |
return z | |
} | |
func sqrt(x float64) float64 { | |
return math.Sqrt(x) | |
} | |
func main() { | |
// fmt.Println(Sqrt(2)) | |
times := 10 | |
for i := 1; i <= times; i++ { | |
sqrt := sqrt(float64(i)) | |
newt := newton(float64(i)) | |
fmt.Printf("input %d \t", i) | |
fmt.Printf("math.Sqrt: %v \t", sqrt) | |
fmt.Println() | |
fmt.Printf("\t\t") | |
fmt.Printf("newton: %v \t", newt) | |
fmt.Println() | |
fmt.Printf("\t\t") | |
fmt.Printf("difference: %v \t", math.Abs(sqrt - newt)) | |
fmt.Println() | |
} | |
} | |
// exercise-slices.go --------------------------------------------- | |
package main | |
import "golang.org/x/tour/pic" | |
func Pic(dx, dy int) [][]uint8 { | |
ret := make([][]uint8, dy) | |
// make rows | |
for i := range ret { | |
ret[i] = make([]uint8, dx) | |
// make pixels | |
for ii := range ret[i]; { | |
x := ii | |
y := i | |
ret[i][ii] = uint8(x^y); | |
} | |
} | |
return ret | |
} | |
func main() { | |
pic.Show(Pic) | |
} | |
// exercise-maps.go ----------------------------------------------- | |
package main | |
import ( | |
"golang.org/x/tour/wc" | |
"strings" | |
) | |
func WordCount(s string) map[string]int { | |
ret := make(map[string]int) | |
words := strings.Fields(s) | |
for _, v := range words { | |
ret[v] += 1 | |
} | |
return ret | |
} | |
func main() { | |
wc.Test(WordCount) | |
} | |
// exercise-fibonacci-closure.go ---------------------------------- | |
package main | |
import "fmt" | |
// fibonacci is a function that returns | |
// a function that returns an int. | |
func fibonacci() func() int { | |
fa := -1 | |
fb := 1 | |
return func() int { | |
tmp := fa + fb | |
fa = fb | |
fb = tmp | |
return fb | |
} | |
} | |
func main() { | |
f := fibonacci() | |
for i := 0; i < 10; i++ { | |
fmt.Println(f()) | |
} | |
} | |
// exercise-stringer.go ------------------------------------------- | |
package main | |
import "fmt" | |
type IPAddr [4]byte | |
func (ipAddr IPAddr) String() string { | |
return fmt.Sprintf("%d.%d.%d.%d", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[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) | |
} | |
} | |
// exercise-errors.go --------------------------------------------- | |
package main | |
import ( | |
"fmt" | |
"math" | |
) | |
type ErrNegativeSqrt float64 | |
func (e ErrNegativeSqrt) Error() string { | |
return fmt.Sprint("cannot Sqrt negative number:", float64(e)) | |
} | |
func Sqrt(x float64) (float64, error) { | |
if x < 0 {return 0, ErrNegativeSqrt(x)} | |
return math.Sqrt(x), nil | |
} | |
func main() { | |
fmt.Println(Sqrt(2)) | |
fmt.Println(Sqrt(-2)) | |
} | |
// exercise-reader.go --------------------------------------------- | |
package main | |
import "github.com/Go-zh/tour/reader" | |
type MyReader struct{} | |
func (reader MyReader) Read(b []byte) (int, error) { | |
b[0] = 'A' | |
// Number of bits read, error | |
return 1, nil | |
} | |
func main() { | |
reader.Validate(MyReader{}) | |
} | |
// exercise-rot-reader.go ----------------------------------------- | |
package main | |
import ( | |
"io" | |
"os" | |
"strings" | |
) | |
type rot13Reader struct { | |
r io.Reader | |
} | |
func (reader rot13Reader) Read(b []byte) (int, error) { | |
n, err := reader.r.Read(b) | |
for i := 0; i < n; i++ { | |
if (b[i] >= 'A' && b[i] < 'N') || (b[i] >= 'a' && b[i] < 'n') { | |
b[i] += 13 | |
} else if (b[i] > 'M' && b[i] <= 'Z') || (b[i] > 'm' && b[i] <= 'z') { | |
b[i] -= 13 | |
} | |
} | |
return n, err | |
} | |
func main() { | |
s := strings.NewReader("Lbh penpxrq gur pbqr!") | |
r := rot13Reader{s} | |
io.Copy(os.Stdout, &r) | |
} | |
// exercise-images.go --------------------------------------------- | |
package main | |
import ( | |
"golang.org/x/tour/pic" | |
"image" | |
"image/color" | |
) | |
type Image struct{ | |
width int | |
height int | |
colorModel color.Model | |
pixels [][]uint8 | |
} | |
func MakeImage(width, height int, colorModel color.Model) Image { | |
return Image{width, height, colorModel, nil} | |
} | |
func (this *Image) generateImage() { | |
this.pixels = make([][]uint8, this.height) | |
for y := 0; y < this.height; y++ { | |
this.pixels[y] = make([]uint8, this.width) | |
for x:= 0; x < this.width; x++ { | |
this.pixels[y][x] = uint8(x^y) | |
} | |
} | |
} | |
// ColorModel returns the Image's color model. | |
func (this Image) ColorModel() color.Model { | |
return this.colorModel | |
} | |
// Bounds returns the domain for which At can return non-zero color. | |
// The bounds do not necessarily contain the point (0, 0). | |
func (this Image) Bounds() image.Rectangle { | |
return image.Rect(0, 0, this.width, this.height) | |
} | |
// At returns the color of the pixel at (x, y). | |
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid. | |
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one. | |
func (this Image) At(x, y int) color.Color { | |
return color.RGBA{this.pixels[y][x], this.pixels[y][x], 255, 255} | |
} | |
func main() { | |
m := MakeImage(256, 256, color.RGBAModel) | |
m.generateImage() | |
pic.ShowImage(m) | |
} | |
// exercise-equivalent-binary-trees.go ---------------------------- | |
package main | |
import "golang.org/x/tour/tree" | |
import "fmt" | |
/* | |
type Tree struct { | |
Left *Tree | |
Value int | |
Right *Tree | |
} | |
*/ | |
// Walk traverse tree t, send value to ch from small to big | |
func Walk(t *tree.Tree, ch chan int) { | |
walkRec(t, ch) | |
close(ch) // must close since using a infinite loop | |
} | |
// recursive helper | |
func walkRec(t *tree.Tree, ch chan int) { | |
// In-order traversal | |
if t.Left != nil {walkRec(t.Left, ch)} | |
ch <- t.Value | |
if t.Right != nil {walkRec(t.Right, ch)} | |
} | |
// detimer if t1 t2 contain same values | |
func Same(t1, t2 *tree.Tree) bool { | |
c1 := make(chan int) | |
c2 := make(chan int) | |
go Walk(t1, c1) | |
go Walk(t2, c2) | |
for node := range c1 { | |
if node != <- c2 {return false} | |
} | |
return true | |
} | |
func main() { | |
fmt.Println("Test for Walk() function:") | |
t := tree.New(1) | |
ch := make(chan int) | |
go Walk(t, ch) | |
for node := range ch { | |
fmt.Println(node) | |
} | |
fmt.Println("Test for Same() function:") | |
fmt.Println("expect true:", Same(tree.New(1), tree.New(1))) | |
fmt.Println("expect false:", Same(tree.New(1), tree.New(2))) | |
} | |
// exercise-web-crawler.go ---------------------------------------- | |
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 CacheMap struct { | |
cache map[string] bool | |
mux sync.Mutex | |
} | |
func (cm *CacheMap) Set(key string) { | |
cm.mux.Lock() | |
cm.cache[key] = true | |
cm.mux.Unlock() | |
} | |
func (cm *CacheMap) Get(key string) bool { | |
cm.mux.Lock() | |
defer cm.mux.Unlock() | |
return cm.cache[key] | |
} | |
// 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, cache CacheMap) { | |
defer close(ret) | |
if depth <= 0 { | |
return | |
} | |
// Don't fetch the same URL twice. | |
if cache.Get(url) { | |
return | |
} | |
body, urls, err := fetcher.Fetch(url) | |
if err != nil { | |
ret <- fmt.Sprintln(err) | |
return | |
} | |
ret <- fmt.Sprintf("found: %s %q\n", url, body) | |
cache.Set(url) | |
subRets := make([]chan string, len(urls)) | |
// Fetch URLs in parallel. | |
for i, u := range urls { | |
subRets[i] = make(chan string) | |
go Crawl(u, depth-1, fetcher, subRets[i], cache) | |
for s := range subRets[i] { | |
ret <- s | |
} | |
} | |
return | |
} | |
func main() { | |
ret := make(chan string) | |
cache := CacheMap{cache: make(map[string] bool)} | |
go Crawl("http://golang.org/", 4, fetcher, ret, cache) | |
for msg := range ret { | |
fmt.Print(msg) | |
} | |
} | |
// 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{ | |
"http://golang.org/": &fakeResult{ | |
"The Go Programming Language", | |
[]string{ | |
"http://golang.org/pkg/", | |
"http://golang.org/cmd/", | |
}, | |
}, | |
"http://golang.org/pkg/": &fakeResult{ | |
"Packages", | |
[]string{ | |
"http://golang.org/", | |
"http://golang.org/cmd/", | |
"http://golang.org/pkg/fmt/", | |
"http://golang.org/pkg/os/", | |
}, | |
}, | |
"http://golang.org/pkg/fmt/": &fakeResult{ | |
"Package fmt", | |
[]string{ | |
"http://golang.org/", | |
"http://golang.org/pkg/", | |
}, | |
}, | |
"http://golang.org/pkg/os/": &fakeResult{ | |
"Package os", | |
[]string{ | |
"http://golang.org/", | |
"http://golang.org/pkg/", | |
}, | |
}, | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment