Last active
September 22, 2016 00:22
-
-
Save danielemoraschi/742dffb417944288c9d17170b3985d9a to your computer and use it in GitHub Desktop.
A Tour of Go - Exercises
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
package main | |
import ( | |
"fmt" | |
"sync" | |
"net/url" | |
) | |
var mu = &sync.Mutex{} | |
func main() { | |
var wg sync.WaitGroup | |
urlToVisit := "http://golang.org/" | |
uniqueVisitPolicy := UniqueUrlPolicyFactory() | |
sameDomainPolicy := SameDomainPolicyFactory(urlToVisit) | |
policies := make([]PolicyInterface, 0) | |
policies = append(policies, uniqueVisitPolicy) | |
policies = append(policies, sameDomainPolicy) | |
var urlList []string | |
urlList = append(urlList, urlToVisit) | |
wg.Add(1) | |
Crawl(&urlList, &wg, urlToVisit, 2, fetcher, policies) | |
wg.Wait() | |
urlList = removeDuplicatesUnordered(urlList) | |
fmt.Println("ALL: %s", urlList) | |
} | |
func removeDuplicatesUnordered(elements []string) []string { | |
encountered := map[string]bool{} | |
// Create a map of all unique elements. | |
for v := range elements { | |
encountered[elements[v]] = true | |
} | |
// Place all keys from the map into a slice. | |
result := []string{} | |
for key := range encountered { | |
result = append(result, key) | |
} | |
return result | |
} | |
// CRAWLER --------------------------------------------------------------------- | |
// Crawl uses fetcher to recursively crawl | |
// pages starting with url, to a maximum of depth. | |
func Crawl(urlsList *[]string, wg *sync.WaitGroup, url string, depth int, | |
fetcher FetcherInterface, policies []PolicyInterface) { | |
defer wg.Done() | |
UrlAllowedByPolicies(policies, url) | |
//fmt.Printf("Visiting: %s\n", url) | |
_, urls, err := fetcher.Fetch(url) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
//fmt.Printf("Found: %s %q\n", urls, body) | |
mu.Lock() | |
*urlsList = append(*urlsList, urls...) | |
mu.Unlock() | |
if depth <= 0 { | |
return | |
} | |
for _, u := range urls { | |
if UrlAllowedByPolicies(policies, u) { | |
wg.Add(1) | |
go Crawl(urlsList, wg, u, depth-1, fetcher, policies) | |
} | |
} | |
return | |
} | |
// POLICIES -------------------------------------------------------------------- | |
type PolicyInterface interface { | |
// Fetch returns the body of URL and | |
// a slice of URLs found on that page. | |
ShouldVisit(url string) bool | |
} | |
func UrlAllowedByPolicies(policies []PolicyInterface, url string) bool { | |
for i := 0; i < len(policies); i++ { | |
if ! policies[i].ShouldVisit(url) { | |
return false | |
} | |
} | |
return true | |
} | |
type UniqueUrlPolicy struct { | |
sync.Mutex | |
urlMap map[string]bool | |
PolicyInterface | |
} | |
func (p UniqueUrlPolicy) ShouldVisit(url string) bool { | |
p.Lock() | |
_, ok := p.urlMap[url] | |
p.urlMap[url] = true | |
p.Unlock() | |
return !ok | |
} | |
func UniqueUrlPolicyFactory() PolicyInterface { | |
p := UniqueUrlPolicy{urlMap: make(map[string]bool)} | |
return p | |
} | |
type SameDomainPolicy struct { | |
baseURL *url.URL | |
PolicyInterface | |
} | |
func (p SameDomainPolicy) ShouldVisit(u string) bool { | |
urlToCheck, err := url.ParseRequestURI(u) | |
if err != nil { | |
panic(err) | |
} | |
ret := p.baseURL.Host == urlToCheck.Host | |
//fmt.Printf("Checking: %s vs %s\n", p.baseURL.Host, urlToCheck.Host) | |
return ret | |
} | |
func SameDomainPolicyFactory(baseUrl string) PolicyInterface { | |
URL, err := url.ParseRequestURI(baseUrl) | |
if err != nil { | |
panic(err) | |
} | |
p := SameDomainPolicy{baseURL: URL} | |
return p | |
} | |
// FETCHERS -------------------------------------------------------------------- | |
type FetcherInterface interface { | |
// Fetch returns the body of URL and | |
// a slice of URLs found on that page. | |
Fetch(url string) (string, []string, error) | |
} | |
// 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://go.com/", | |
"http://golang.org/", | |
"http://golang.org/pkg/", | |
}, | |
}, | |
"http://go.com/": &fakeResult{ | |
"Go Base", | |
[]string{ | |
"http://go.com/re1", | |
"http://go.com/re2", | |
}, | |
}, | |
"http://go.com/re1": &fakeResult{ | |
"Go R1", | |
[]string{ | |
"http://golang.org/", | |
}, | |
}, | |
} |
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
package main | |
import ( | |
"fmt" | |
"math" | |
) | |
func Sqrt(x float64) (float64, error) { | |
if x < 0 { | |
return x, ErrNegativeSqrt(x) | |
} | |
return math.Sqrt(x), nil | |
} | |
type ErrNegativeSqrt float64 | |
func (e ErrNegativeSqrt) Error() string { | |
return fmt.Sprintf("Cannot Sqrt negative number: %f", e) | |
} | |
func main() { | |
fmt.Println(Sqrt(2)) | |
fmt.Println(Sqrt(-2)) | |
} |
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
package main | |
import "fmt" | |
// 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 | |
func fibonacci() func() int { | |
current, next := 0, 1 | |
return func() int { | |
ret := current | |
current, next = next, current + next | |
return ret | |
} | |
} | |
func main() { | |
f := fibonacci() | |
for i := 0; i < 10; i++ { | |
fmt.Println(f()) | |
} | |
} |
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
package main | |
import ( | |
"fmt" | |
"math" | |
) | |
func Round(f float64, places int) (float64) { | |
shift := math.Pow(10, float64(places)) | |
return math.Floor(f * shift + .5) / shift; | |
} | |
func Sqrt(x float64) float64 { | |
z := 1.0 | |
for i := 0.; i < 500; i++ { | |
z = z - (z * z - x) / (2 * z) | |
} | |
return z | |
} | |
func main() { | |
for i := 0.; i < 100; i++ { | |
fmt.Println("Fake for", i, ":", Round(Sqrt(i), 5)) | |
fmt.Println("Real for", i, ":", Round(math.Sqrt(i), 5)) | |
} | |
} |
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
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 _, word := range words { | |
ret[word] = ret[word] + 1 | |
} | |
return ret | |
} | |
func main() { | |
wc.Test(WordCount) | |
} |
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
package main | |
import ( | |
"golang.org/x/tour/pic" | |
) | |
func Pic(dx, dy int) [][]uint8 { | |
vs := make([][]uint8, dy) | |
for y := 0; y < dy; y++ { | |
vs[y] = make([]uint8, dx) | |
for x := 0; x < dx; x++ { | |
vs[y][x] = uint8( y^x ) | |
} | |
} | |
return vs | |
} | |
func main() { | |
pic.Show(Pic) | |
} |
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
package main | |
import "golang.org/x/tour/pic" | |
import ( | |
"image/color" | |
"image" | |
) | |
type Image struct{} | |
func (i Image) ColorModel() color.Model { | |
return color.RGBA64Model | |
} | |
func (i Image) Bounds() image.Rectangle { | |
return image.Rect(0, 0, 50, 50) | |
} | |
func (i Image) At(x, y int) color.Color { | |
return color.RGBA{20, 60, 30, 0} | |
} | |
func main() { | |
m := Image{} | |
pic.ShowImage(m) | |
} |
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
package main | |
import "fmt" | |
type SimCardInterface interface { | |
GetNumber() string | |
} | |
type SimCard struct { | |
number string | |
} | |
func (d SimCard) GetNumber() string { | |
return d.number | |
} | |
type PhoneInterface interface { | |
Call() string | |
} | |
type Phone struct { } | |
func (p Phone) Call() string { | |
return "Ring Ring" | |
} | |
type CameraInterface interface { | |
TakePicture() string | |
} | |
type Camera struct { } | |
func (c Camera) TakePicture() string { | |
return "Click" | |
} | |
type SmartPhoneInterface interface { | |
SimCardInterface | |
PhoneInterface | |
CameraInterface | |
} | |
// multiple inheritance | |
type SmartPhone struct { | |
SimCard //has anonymous sim card | |
Camera //has anonymous camera | |
Phone //has anonymous phone | |
} | |
func main() { | |
var phone SmartPhoneInterface = SmartPhone{ | |
SimCard: SimCard{number: "+44770000000"}, | |
} | |
fmt.Println("Our new SmartPhone exhibits multiple behaviors ...") | |
fmt.Println("It has a telephone number: ", phone.GetNumber()) | |
fmt.Println("It can take a picture: ", phone.TakePicture()) | |
fmt.Println("It can also make calls: ", phone.Call()) | |
} |
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
package main | |
import "fmt" | |
type Store interface { | |
GetLocation() string | |
String() string | |
} | |
type Tesco struct { | |
location string | |
} | |
func (t *Tesco) GetLocation() string { | |
return t.location | |
} | |
func (t *Tesco) String() string { | |
return fmt.Sprintf("Location \"%v\"", t.GetLocation()) | |
} | |
func main() { | |
var store Store = &Tesco{"London"} | |
fmt.Println(store) | |
} |
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
package main | |
import ( | |
"fmt" | |
) | |
func MaxProfit(list []int) int { | |
max, length := -1, len(list) | |
for i:=0; i<length; i++ { | |
for j:=i+1; j<length; j++ { | |
r := list[j] - list[i] | |
if r > 0 && r > max { | |
max = r | |
} | |
} | |
} | |
return max | |
} | |
func main() { | |
list := []int{45, 24, 35, 31, 40, 38, 11, } | |
fmt.Printf("MAx profit %v", MaxProfit(list)) | |
} |
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
package main | |
import "fmt" | |
func factorial(x int) (result int) { | |
if x == 0 { | |
result = 1 | |
} else { | |
result = x * factorial(x-1) | |
} | |
return | |
} | |
func permute(pos int, len int, set *[]int) { | |
if pos == len { | |
fmt.Printf("Perm: %v\n", set) | |
return | |
} | |
for i := pos; i < len; i++ { | |
(*set)[pos], (*set)[i] = (*set)[i], (*set)[pos] | |
permute(pos+1, len, set) | |
(*set)[pos], (*set)[i] = (*set)[i], (*set)[pos] | |
} | |
} | |
func main() { | |
set := []int{1, 2, 3, } | |
repeat := factorial(len(set)) | |
fmt.Printf("Tot permutations: %v\n", repeat) | |
permute(0, len(set), &set) | |
fmt.Printf("Tot permutations: %v\n", repeat) | |
} |
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
package main | |
import ( | |
"fmt" | |
) | |
func fib(num int) int { | |
if (num == 0 || num == 1) { | |
return num | |
} | |
ret := fib(num-1) + fib(num-2) | |
return ret | |
} | |
func fib2() func() int { | |
x, p1, p2 := 0, 1, 1 | |
return func() int { | |
if (x == 0 || x == 1) { | |
x++ | |
} | |
x++ | |
} | |
} | |
func fibonacci(n int, c chan int) { | |
x, y := 0, 1 | |
for i := 0; i < n; i++ { | |
c <- x | |
x, y = y, x+y | |
} | |
close(c) | |
} | |
func main() { | |
f := fib2() | |
for i := 0; i < 10; i++ { | |
fmt.Println(f()) | |
} | |
fmt.Println("----------") | |
for i := 0; i < 10; i++ { | |
fmt.Println(fib(i)) | |
} | |
fmt.Println("----------") | |
c := make(chan int, 10) | |
go fibonacci(cap(c), c) | |
for i := range c { | |
fmt.Println(i) | |
} | |
} |
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
package main | |
import ( | |
"io" | |
"os" | |
"strings" | |
) | |
func rot13(p []byte) []byte { | |
for i := 0; i < len(p); i++ { | |
if (p[i] >= 'A' && p[i] < 'N') || (p[i] >='a' && p[i] < 'n') { | |
p[i] += 13 | |
} else if (p[i] > 'M' && p[i] <= 'Z') || (p[i] > 'm' && p[i] <= 'z'){ | |
p[i] -= 13 | |
} | |
} | |
return p | |
} | |
type rot13Reader struct { | |
r io.Reader | |
} | |
func (rot rot13Reader) Read(b []byte) (n int, err error) { | |
n, e := rot.r.Read(b) | |
rot13(b) | |
return len(b), e | |
} | |
func main() { | |
s := strings.NewReader("Lbh penpxrq gur pbqr!") | |
r := rot13Reader{s} | |
io.Copy(os.Stdout, &r) | |
} |
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
package main | |
import "fmt" | |
type IPAddr [4]byte | |
func (t IPAddr) String() string { | |
return fmt.Sprintf("%d.%d.%d.%d", t[0], t[1], t[2], t[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) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment