A => go.mod +5 -0
@@ 1,5 @@
+module go-play
+
+go 1.16
+
+require golang.org/x/tour v0.1.0
A => go.sum +2 -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=
A => misc/factorial.go +24 -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))
+}
A => tour/concurrency/10_webCrawler.go +102 -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/",
+ },
+ },
+ }
A => tour/methods/09_interfaces.go +41 -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"
+}
A => tour/methods/14_emptyInterface.go +22 -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)
+}
A => tour/methods/16_typeSwitches.go +33 -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))
+}
A => tour/methods/18_stringers.go +29 -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)
+ }
+}
A => tour/methods/19_errors.go +32 -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)
+ }
+ }
A => tour/methods/22_AReader.go +23 -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{})
+}
A => tour/methods/23_rot13Reader.go +94 -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)
+}
A => tour/methods/25_imageInterface.go +37 -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)
+}
A => tour/moretypes/18_slicesBluescalePic.go +21 -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)
+}
A => tour/moretypes/23_wordCount.go +33 -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"))
+}
A => tour/moretypes/25_highOrderFunc.go +22 -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
+}
A => tour/moretypes/26_fibonacciClosure.go +23 -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())
+ }
+}