From 4434d0f2e1b13683d1d24658f1b600fb17abdd9a Mon Sep 17 00:00:00 2001 From: Hedy Li Date: Fri, 23 Jul 2021 09:52:05 +0800 Subject: [PATCH] add everything --- go.mod | 5 ++ go.sum | 2 + misc/factorial.go | 24 ++++++ tour/concurrency/10_webCrawler.go | 102 ++++++++++++++++++++++++ tour/methods/09_interfaces.go | 41 ++++++++++ tour/methods/14_emptyInterface.go | 22 +++++ tour/methods/16_typeSwitches.go | 33 ++++++++ tour/methods/18_stringers.go | 29 +++++++ tour/methods/19_errors.go | 32 ++++++++ tour/methods/22_AReader.go | 23 ++++++ tour/methods/23_rot13Reader.go | 94 ++++++++++++++++++++++ tour/methods/25_imageInterface.go | 37 +++++++++ tour/moretypes/18_slicesBluescalePic.go | 21 +++++ tour/moretypes/23_wordCount.go | 33 ++++++++ tour/moretypes/25_highOrderFunc.go | 22 +++++ tour/moretypes/26_fibonacciClosure.go | 23 ++++++ 16 files changed, 543 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 misc/factorial.go create mode 100644 tour/concurrency/10_webCrawler.go create mode 100644 tour/methods/09_interfaces.go create mode 100644 tour/methods/14_emptyInterface.go create mode 100644 tour/methods/16_typeSwitches.go create mode 100644 tour/methods/18_stringers.go create mode 100644 tour/methods/19_errors.go create mode 100644 tour/methods/22_AReader.go create mode 100644 tour/methods/23_rot13Reader.go create mode 100644 tour/methods/25_imageInterface.go create mode 100644 tour/moretypes/18_slicesBluescalePic.go create mode 100644 tour/moretypes/23_wordCount.go create mode 100644 tour/moretypes/25_highOrderFunc.go create mode 100644 tour/moretypes/26_fibonacciClosure.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bc2f047 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module go-play + +go 1.16 + +require golang.org/x/tour v0.1.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cde48ea --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/tour v0.1.0 h1:OWzbINRoGf1wwBhKdFDpYwM88NM0d1SL/Nj6PagS6YE= +golang.org/x/tour v0.1.0/go.mod h1:DUZC6G8mR1AXgXy73r8qt/G5RsefKIlSj6jBMc8b9Wc= diff --git a/misc/factorial.go b/misc/factorial.go new file mode 100644 index 0000000..5f1069c --- /dev/null +++ b/misc/factorial.go @@ -0,0 +1,24 @@ +/* factorial recursion and loop */ + +package misc + +import "fmt" + +func factorial(n int) int { + // recursion + if n == 0 || n == 1 { return 1 }; return n * factorial(n-1) +} + +func factorialLoop(n int) int { + // loop + result := 1 + for n>=1 { + result *= n; n-- + } + return result +} + +func main() { + fmt.Println(factorial(5)) + fmt.Println(factorialLoop(5)) +} diff --git a/tour/concurrency/10_webCrawler.go b/tour/concurrency/10_webCrawler.go new file mode 100644 index 0000000..126720c --- /dev/null +++ b/tour/concurrency/10_webCrawler.go @@ -0,0 +1,102 @@ +// Crawl through fetcher map asynchronosly (?) and avoiding fetching duplicates + +package concurrency + +import ( + "fmt" + "time" +) + + +// Crawl uses fetcher to recursively crawl +// pages starting with url, to a maximum of depth. +func Crawl(url string, depth int, fetcher Fetcher) { + for _, v := range stored { + if v == url { return } + } + stored = append(stored, url) + if depth <= 0 { + return + } + body, urls, err := fetcher.Fetch(url) + if err != nil { + fmt.Println(err) + return + } + fmt.Printf("found: %s %q\n", url, body) + //done <- true + for _, u := range urls { + go Crawl(u, depth-1, fetcher) + } + return +} + +func main() { + Crawl("https://golang.org/", 4, fetcher) + //<-done + time.Sleep(time.Second) +} + + +// ----------------- storage stuff ----------------- + +var stored []string // fetched urls +//var done chan bool + + +// ----------------- fetcher stuff ----------------- + +// fakeFetcher is Fetcher that returns canned results. +type fakeFetcher map[string]*fakeResult + +type fakeResult struct { + body string + urls []string +} + +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) +} + +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/", + }, + }, + } diff --git a/tour/methods/09_interfaces.go b/tour/methods/09_interfaces.go new file mode 100644 index 0000000..aa05ca2 --- /dev/null +++ b/tour/methods/09_interfaces.go @@ -0,0 +1,41 @@ +/* +# Interfaces + +https://tour.golang.org/methods/9 +*/ + +package methods + +import ( + "fmt" + "strings" +) + +type Speaker interface { + speak() string +} + +// ********************************* + +func main() { + var s Speaker + r := Dog{"Roddy", "Brown", []string{"im created!", "im a doggy!"}} + + s = &r + + fmt.Println(r.name, "says", s.speak()) + fmt.Println("So far", r.name, "had said:\n -", strings.Join(r.speech, "\n - ")) + fmt.Println(r.name, "speaks again!", r.speak()) +} + +// ********************************* + +type Dog struct { + name, color string + speech []string +} + +func (d *Dog) speak() string { + d.speech = append(d.speech, "woof") + return "woof" +} diff --git a/tour/methods/14_emptyInterface.go b/tour/methods/14_emptyInterface.go new file mode 100644 index 0000000..b1bfc9a --- /dev/null +++ b/tour/methods/14_emptyInterface.go @@ -0,0 +1,22 @@ +/* +# Empty interface + +https://tour.golang.org/methods/14 +*/ + +package methods + +import ( + "fmt" +) + +func main() { + typePrint("hi") +} + +// Prints argument type to stderr +// then prints the argument to stdout with newline +func typePrint(i interface{}) { + print(fmt.Sprintf("%T", i) + "\n") + fmt.Println(i) +} diff --git a/tour/methods/16_typeSwitches.go b/tour/methods/16_typeSwitches.go new file mode 100644 index 0000000..a70015f --- /dev/null +++ b/tour/methods/16_typeSwitches.go @@ -0,0 +1,33 @@ +/* type switches https://tour.golang.org/methods/16 */ + +package methods + +import "fmt" + +func tryType(i interface{}) { + switch v := i.(type) { + case int: + fmt.Printf("Twice %v is %v\n", v, v*2) + case float64: + fmt.Printf("%v rounded to 2dp is: %.2f\n", v, v) + case string: + fmt.Printf("%q is %v bytes long\n", v, len(v)) // %q = quoted + case bool: + fmt.Printf("!%v is %v\n", v, !v) + case []int: + fmt.Printf("int slice has capacity %v and length %v\n", cap(v), len(v)) + case map[string]int: + fmt.Printf("Map with key as string, value as int has %v items in it\n", len(v)) + default: + fmt.Printf("Type %T with syntax %#v unknown!\n", v, v) + } +} + +func main() { + tryType(21) + tryType("hello") + tryType(true) + tryType(2.1313) + tryType(make([]int, 2)) + tryType(make(map[string]int)) +} diff --git a/tour/methods/18_stringers.go b/tour/methods/18_stringers.go new file mode 100644 index 0000000..5f59e2d --- /dev/null +++ b/tour/methods/18_stringers.go @@ -0,0 +1,29 @@ +/* Stringers (exercise) https://tour.golang.org/methods/18 */ + +package methods + +import ( + "fmt" + "strings" +) + +type IPAddr [4]byte + +func (ip IPAddr) String() string { + var ipStr []string + for _, v := range ip { // array byte to string + // not sure if there's a better way for this than fmt.Sprintf + ipStr = append(ipStr, fmt.Sprintf("%v", v)) + } + return strings.Join(ipStr, ".") +} + +func main() { + hosts := map[string]IPAddr{ + "loopback": {127, 0, 0, 1}, + "googleDNS": {8, 8, 8, 8}, + } + for name, ip := range hosts { // print "name: ip" + fmt.Printf("%v: %v\n", name, ip) + } +} diff --git a/tour/methods/19_errors.go b/tour/methods/19_errors.go new file mode 100644 index 0000000..7cd661a --- /dev/null +++ b/tour/methods/19_errors.go @@ -0,0 +1,32 @@ +/* Errors https://tour.golang.org/methods/19 */ + +package methods + +import ( + "fmt" +) + +type ZeroError struct { + TryInstead int + Reason string +} + +func (e *ZeroError) Error() string { + return fmt.Sprintln( + "Zero not allowed, because", + e.Reason+".", "Maybe try", + e.TryInstead, "instead.") + } + + func minus1(n int) (int, error) { + if n != 0 { + return n - 1, nil + } + return 0, &ZeroError{5, "I said so"} + } + + func main() { + if _, err := minus1(0); err != nil { + panic(err) + } + } diff --git a/tour/methods/22_AReader.go b/tour/methods/22_AReader.go new file mode 100644 index 0000000..2dee843 --- /dev/null +++ b/tour/methods/22_AReader.go @@ -0,0 +1,23 @@ +// Readers Exercise - A reader type that emits an infinite stream of 'A' +// https://tour.golang.org/methods/22 + +package methods + +import "golang.org/x/tour/reader" + +type MyReader struct{} + +// Read just fills b with 'A' and yeah, that's all it does +// honestly I didn't know changing the value of b would actually +// change it (I thought you'd have to use pointers?) but it did +// pass the test so ok! +func (MyReader) Read(b []byte) (int, error) { + for i := range b { + b[i] = 'A' + } + return len(b), nil +} + +func main() { + reader.Validate(MyReader{}) +} diff --git a/tour/methods/23_rot13Reader.go b/tour/methods/23_rot13Reader.go new file mode 100644 index 0000000..8f042f8 --- /dev/null +++ b/tour/methods/23_rot13Reader.go @@ -0,0 +1,94 @@ +// rot13Reader Exercise +// +// A io.Reader that encrypts or unencrypts its io.Reader contents +// https://tour.golang.org/methods/23 +// +// > Implement a rot13Reader that implements io.Reader and reads +// > from an io.Reader, modifying the stream by applying the +// > rot13 substitution cipher to all alphabetical characters. +// +// rot13 is literally caesar cipher but with key=13, this just makes +// it so that encryption and decryption is the same because: +// len(letters) / 2 = 13. +// +// Check out rot13 wikipedia for more info + +package methods + +import ( + "io" + "os" + "strings" + "unicode" +) + +var letters string = "abcdefghigklmnopqrstuvwxyz" + +type rot13Reader struct { + r io.Reader + + prevRune int // I have no idea how r.prevRune and r.i work together but + // this strategy is present everywhere in standard libs and + // the program gives no output if I don't do this. + + i int64 // read index + o string // unencrypted text +} + +func (r rot13Reader) Read(b []byte) (n int, err error) { + // Read the crypt text + readByte := make([]byte, 1) + n, err = r.r.Read(readByte) + // Exit immediately if there's no more to read + if err == io.EOF { + return + } + + // Prepare for decryption + oneByte := readByte[0] + up := false + + // Only do the rot13 if the thing is an actual letter + if unicode.IsLetter(rune(oneByte)) { + // Easier to do string manipulation with strings pkg + oneStr := string(oneByte) + + // Lower the string for string indexing, but keep the case later + if strings.ToUpper(oneStr) == oneStr { + up = true + oneStr = strings.ToLower(oneStr) + } + + index := strings.Index(letters, oneStr) + 13 + if index > 25 { + index = index % 26 + } // Wrap around + letter := []rune(letters)[index] // Rotated/result letter + if up { // Preserve original case + letter = []rune(strings.ToUpper(string(letter)))[0] + } + + oneByte = byte(letter) + } + + // This is such an ugly hack as I think of it, but this is just to replace the + // r.s thingy in strings.Reader implementation (as well as in bytes pkg) + r.o += string(oneByte) + + // ---- Begin some random copied shit ---- + if r.i >= int64(len(r.o)) { // As I said above I have no idea how this works + return 0, io.EOF + } + r.prevRune = -1 + n = copy(b, r.o[r.i:]) + r.i += int64(n) + // ---- End some random copied shit ---- + return +} + +func main() { + s := strings.NewReader("Lbh penpxrq gur pbqr!") // => You cracked the code! + // TBH I don't even know if these default values I gave are ok, it works, so yeah. + r := rot13Reader{s, 0, 0, ""} + io.Copy(os.Stdout, &r) +} diff --git a/tour/methods/25_imageInterface.go b/tour/methods/25_imageInterface.go new file mode 100644 index 0000000..0ab4f72 --- /dev/null +++ b/tour/methods/25_imageInterface.go @@ -0,0 +1,37 @@ +// implementing Image interface like the Bluescale Pic generator for slices exercise +// https://tour.golang.org/methods/25 (the other pic generator ^ was /moretypes/18) +// +// Output: https://hedy.smol.pub/imageInterface.png + +package methods + +import ( + "golang.org/x/tour/pic" + "image/color" + "image" +) + +type Image struct{} + +func (i Image) ColorModel() color.Model { + return color.RGBAModel +} + +func (i Image) Bounds() image.Rectangle { + return image.Rect(0, 0, 150, 150) +} + +func (i Image) At(x, y int) color.Color { + var r, g, b, a int + // nothing fancy like 2^((x-y)/(x+3)^x)^x or something lol + r = 2^x+y // but this still produces a somewhat weird image 0_0 + g = 70 + b = 200 + a = 200 + return color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)} +} + +func main() { + m := Image{} + pic.ShowImage(m) +} diff --git a/tour/moretypes/18_slicesBluescalePic.go b/tour/moretypes/18_slicesBluescalePic.go new file mode 100644 index 0000000..d44293d --- /dev/null +++ b/tour/moretypes/18_slicesBluescalePic.go @@ -0,0 +1,21 @@ +/* https://tour.golang.org/moretypes/18 */ + +package moretypes + +import "golang.org/x/tour/pic" + +func Pic(dx, dy int) [][]uint8 { + var a [][]uint8 + var b []uint8 + for i := range make([]uint8, 256) { + for j := range make([]uint8, 256) { + b = append(b, uint8(2^(i-j))) + } + a = append(a, b) + } + return a[:dy][:dx] +} + +func main() { + pic.Show(Pic) +} diff --git a/tour/moretypes/23_wordCount.go b/tour/moretypes/23_wordCount.go new file mode 100644 index 0000000..391d3d7 --- /dev/null +++ b/tour/moretypes/23_wordCount.go @@ -0,0 +1,33 @@ +/* https://tour.golang.org/moretypes/23 */ + +package moretypes + +import ( + "golang.org/x/tour/wc" + "strings" + //"fmt" +) + +func itemCount(a []string, sub string) int { + var count int + for _, v := range a { + if v == sub { + count++ + } + } + return count +} + +func WordCount(s string) map[string]int { + m := make(map[string]int) + strs := strings.Fields(s) + for _, v := range strs { + m[v] = itemCount(strs, v) + } + return m +} + +func main() { + wc.Test(WordCount) + //fmt.Println(WordCount("a a b")) +} diff --git a/tour/moretypes/25_highOrderFunc.go b/tour/moretypes/25_highOrderFunc.go new file mode 100644 index 0000000..e1be10b --- /dev/null +++ b/tour/moretypes/25_highOrderFunc.go @@ -0,0 +1,22 @@ +// func that returns a func +// https://tour.golang.org/moretypes/25 +// Classic example when learning high order funcs + +package moretypes + +import ( + "fmt" +) + +func makeAdder(addWhat int) func(a int) int { + return func(a int) int { + return a + addWhat + } +} + +func main() { + add2 := makeAdder(2) + fmt.Println(add2(2)) // 2+2 + add1 := makeAdder(1) + fmt.Println(add1(3)) // 3+1 +} diff --git a/tour/moretypes/26_fibonacciClosure.go b/tour/moretypes/26_fibonacciClosure.go new file mode 100644 index 0000000..9c2bcaf --- /dev/null +++ b/tour/moretypes/26_fibonacciClosure.go @@ -0,0 +1,23 @@ +/* https://tour.golang.org/moretypes/26 */ + +package moretypes + +import "fmt" + +// fibonacci is a function that returns a function that returns an int. +// It's closure, duh +func fibonacci() func() int { + a, b := 0, 0 + return func() int { + a, b = b, a+b + if b == 0 { a++ } + return b + } +} + +func main() { + f := fibonacci() + for i := 0; i < 7; i++ { + fmt.Println(f()) + } +} -- 2.45.2