Skip to content

Instantly share code, notes, and snippets.

@lleo
Created January 29, 2016 22:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lleo/35dac91011da56af2d0e to your computer and use it in GitHub Desktop.
Save lleo/35dac91011da56af2d0e to your computer and use it in GitHub Desktop.
My Solutions / answers to tour.golang.org Jan 29, 2016
//Exercise: Web Crawler http://tour.golang.org/concurrency/10
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 syncStringSet struct {
set map[string]bool
mux sync.Mutex
}
// set.add(string) returns true if it does not have string in set, but has now inserted
// the string into the set.
// set.add(url) returns false if it has the url in its cache
func (ss *syncStringSet) add(str string) bool {
ss.mux.Lock()
defer ss.mux.Unlock()
if _, hasEntry := ss.set[str]; hasEntry {
return false
}
ss.set[str] = true
return true
}
type result struct {
url string
body string
err error
}
type crawlError struct {
error
}
func crawl(
url string,
depth int,
fetcher Fetcher,
results chan result,
seen *syncStringSet,
crawlers *sync.WaitGroup,
) {
defer crawlers.Done()
if depth < 1 {
results <- result{
url: url,
err: crawlError{fmt.Errorf("depth exceeded (%d)", depth)},
}
return
}
if !seen.add(url) {
results <- result{
url: url,
err: crawlError{fmt.Errorf("seen.add(%q) == false", url)},
}
return
}
body, urls, err := fetcher.Fetch(url)
for _, u := range urls {
crawlers.Add(1)
go crawl(u, depth-1, fetcher, results, seen, crawlers)
}
results <- result{url, body, err}
}
func Crawl(url string, depth int, fetcher Fetcher) {
seen := &syncStringSet{set: make(map[string]bool)}
crawlers := &sync.WaitGroup{}
results := make(chan result)
//expected_msgs.inc()
crawlers.Add(1)
go crawl(url, depth, fetcher, results, seen, crawlers)
go func() {
crawlers.Wait()
close(results)
}()
for res := range results {
_, isCrawlError := res.err.(crawlError)
switch {
case isCrawlError:
//fmt.Println(res.err)
case res.err != nil:
fmt.Println(res.err)
default:
fmt.Printf("found: %s %q\n", res.url, res.body)
}
}
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
// 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/",
},
},
}
// Exercise: Equivalent Binary Trees http://tour.golang.org/concurrency/8
//
// 1. Implement the Walk function.
//
// 2. Test the Walk function.
//
// The function tree.New(k) constructs a randomly-structured binary tree
// holding the values k, 2k, 3k, ..., 10k.
//
// Create a new channel ch and kick off the walker:
//
// go Walk(tree.New(1), ch)
//
// Then read and print 10 values from the channel. It should be the numbers
// 1, 2, 3, ..., 10.
//
// 3. Implement the Same function using Walk to determine whether t1 and t2
// store the same values.
//
// 4. Test the Same function.
//
// Same(tree.New(1), tree.New(1)) should return true, and Same(tree.New(1),
// tree.New(2)) should return false.
package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
if t.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 {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i:=0; i<10; i++ {
v1 := <- ch1
v2 := <- ch2
if v1 != v2 {
return false
}
}
return true
}
func main() {
if Same(tree.New(1), tree.New(1)) {
fmt.Println("The trees are the same.")
} else {
fmt.Println("The trees are NOT the same.")
}
}
/*
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for i := 0; i < 10; i++ {
fmt.Println(<-ch)
}
}
*/
//Exercise: Loops and Functions http://tour.golang.org/flowcontrol/8
// Next, change the loop condition to stop once the value has stopped changing
// (or only changes by a very small delta). See if that's more or fewer
// iterations. How close are you to the math.Sqrt?
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
delta := 0.0001 //terminates at i=7
//delta := 0.00001 //terminates at i=9
//delta := 0.000001 //terminates at i=11
z := float64(1)
for i := 0; i < 100; i++ {
z0 := z
z = z - ((z*z - x) / (2*x))
if math.Abs(z-z0) < delta {
fmt.Printf("small enough i=%d, delta=%f\n", i, delta)
break
}
}
return z
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println("math.Sqrt(2) =", math.Sqrt(2))
}
//Exercise: Loops and Functions http://tour.golang.org/flowcontrol/8
package main
import (
"fmt"
)
func Sqrt(x float64) float64 {
z := float64(1)
for i := 0; i < 10; i++ {
z = z - ((z*z - x) / (2*x))
}
return z
}
func main() {
fmt.Println(Sqrt(2))
}
//Exercise: Stringers http://tour.golang.org/methods/18
package main
import "fmt"
type IPAddr [4]byte
// TODO: Add a "String() string" method to IPAddr.
func (ip IPAddr) String() string {
return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
}
func main() {
addrs := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for n, a := range addrs {
fmt.Printf("%v: %v\n", n, a)
}
}
//Exercise: Errors http://tour.golang.org/methods/20
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (err ErrNegativeSqrt) Error() string {
return fmt.Sprintf("cannot Sqrt negative number: %d", err)
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return math.NaN(), ErrNegativeSqrt(x)
}
z := float64(1)
for i :=1; i<10; i++ {
z = z - ((z*z)-x)/(2*x)
}
return z, nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
//Exercise: Readers http://tour.golang.org/methods/22
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
func (m MyReader) Read(b []byte) (n int, err error) {
for n = range b {
b[n] = 'A'
}
return
}
func main() {
reader.Validate(MyReader{})
}
//Exercise: rot13Reader http://tour.golang.org/methods/23
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func (rot *rot13Reader) Read(b []byte) (n int, err error) {
n, err = rot.r.Read(b)
for i, v := range b {
switch {
case v >= 'A' && v <= 'Z':
if v < 'N' {
b[i] += 13
} else {
b[i] -= 13
}
case v >= 'a' && v <= 'z':
if v < 'n' {
b[i] += 13
} else {
b[i] -= 13
}
}
}
return
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
//Exercise: Images http://tour.golang.org/methods/25
package main
import (
"golang.org/x/tour/pic"
"image"
"image/color"
)
type Image struct{}
func (i Image) ColorModel() color.Model {
return color.RGBAModel
}
func (i Image) Bounds() image.Rectangle {
return image.Rect(0, 0, 256, 256)
}
func (i Image) At(x, y int) color.Color {
return color.RGBA{72, 72, uint8(x^y), 255}
}
func main() {
m := Image{}
pic.ShowImage(m)
}
//Exercise: Slices http://tour.golang.org/moretypes/15
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
var p = make([]([]uint8), dy)
for y := 0; y < len(p); y++ {
p[y] = make([]uint8, dx)
for x := 0; x < len(p[y]); x++ {
//p[y][x] = uint8((y + x) / 2)
//p[y][x] = uint8(y * x)
p[y][x] = uint8(y ^ x)
}
}
return p
}
func main() {
pic.Show(Pic)
}
//Exercise: Maps http://tour.golang.org/moretypes/20
package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
wordcount := make(map[string]int)
for _, w := range strings.Fields(s) {
wordcount[w]++
}
return wordcount
}
func main() {
wc.Test(WordCount)
}
//Exercise: Fibonacci closure http://tour.golang.org/moretypes/23
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
prev, curr := 0, 1
return func() int {
ret := prev
prev, curr = curr, prev+curr
return ret
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment