From c1b7c64da2aa492576e9cbe67700b7281d88eb7d Mon Sep 17 00:00:00 2001 From: Robert Jeutter Date: Sat, 1 Jan 2022 19:47:24 +0100 Subject: [PATCH] go by example part 2 --- 5-go-by-example/11-range.go | 38 +++++++++++++++ 5-go-by-example/12-function.go | 24 ++++++++++ 5-go-by-example/13-muliple-return-value.go | 20 ++++++++ 5-go-by-example/14-variadic-function.go | 26 ++++++++++ 5-go-by-example/15-closures.go | 29 ++++++++++++ 5-go-by-example/16-recursion.go | 29 ++++++++++++ 5-go-by-example/17-pointers.go | 33 +++++++++++++ 5-go-by-example/18-structs.go | 49 +++++++++++++++++++ 5-go-by-example/19-methods.go | 32 +++++++++++++ 5-go-by-example/20-interfaces.go | 55 ++++++++++++++++++++++ 10 files changed, 335 insertions(+) create mode 100644 5-go-by-example/11-range.go create mode 100644 5-go-by-example/12-function.go create mode 100644 5-go-by-example/13-muliple-return-value.go create mode 100644 5-go-by-example/14-variadic-function.go create mode 100644 5-go-by-example/15-closures.go create mode 100644 5-go-by-example/16-recursion.go create mode 100644 5-go-by-example/17-pointers.go create mode 100644 5-go-by-example/18-structs.go create mode 100644 5-go-by-example/19-methods.go create mode 100644 5-go-by-example/20-interfaces.go diff --git a/5-go-by-example/11-range.go b/5-go-by-example/11-range.go new file mode 100644 index 0000000..42d8783 --- /dev/null +++ b/5-go-by-example/11-range.go @@ -0,0 +1,38 @@ +package main + +import "fmt" + +// range iterates over elements in a variety of data structures +func main() { + + // use range to sum the numbers in a slice + nums := []int{2, 3, 4} + sum := 0 + for _, num := range nums { + sum += num + } + fmt.Println("sum:", sum) + + // range on arrays and slices provides both the index and value for each entry + for i, num := range nums { + if num == 3 { + fmt.Println("index:", i) + } + } + + // range on map iterates over key/value pairs + kvs := map[string]string{"a": "apple", "b": "banana"} + for k, v := range kvs { + fmt.Printf("%s -> %s\n", k, v) + } + + // range iterate over keys of a map + for k := range kvs { + fmt.Println("key:", k) + } + + // range on strings iterates over Unicode code points + for i, c := range "go" { + fmt.Println(i, c) + } +} diff --git a/5-go-by-example/12-function.go b/5-go-by-example/12-function.go new file mode 100644 index 0000000..f38a843 --- /dev/null +++ b/5-go-by-example/12-function.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +// function that takes two ints and returns their sum as an int +// Go requires explicit returns +func plus(a int, b int) int { + return a + b +} + +// multiple consecutive parameters of the same type, +// may omit the type name for the like-typed parameters up to the final parameter that declares the type +func plusPlus(a, b, c int) int { + return a + b + c +} + +func main() { + // Call a function + res := plus(1, 2) + fmt.Println("1+2 =", res) + + res = plusPlus(1, 2, 3) + fmt.Println("1+2+3 =", res) +} diff --git a/5-go-by-example/13-muliple-return-value.go b/5-go-by-example/13-muliple-return-value.go new file mode 100644 index 0000000..38912d8 --- /dev/null +++ b/5-go-by-example/13-muliple-return-value.go @@ -0,0 +1,20 @@ +package main + +import "fmt" + +// (int, int) in this function signature shows that the function returns 2 ints +func vals() (int, int) { + return 3, 7 +} + +func main() { + + // use the 2 different return values + a, b := vals() + fmt.Println(a) + fmt.Println(b) + + // use the blank identifier _ + _, c := vals() + fmt.Println(c) +} diff --git a/5-go-by-example/14-variadic-function.go b/5-go-by-example/14-variadic-function.go new file mode 100644 index 0000000..7c17a47 --- /dev/null +++ b/5-go-by-example/14-variadic-function.go @@ -0,0 +1,26 @@ +package main + +import "fmt" + +// Variadic functions can be called with any number of trailing arguments + +// take an arbitrary number of ints as arguments +func sum(nums ...int) { + fmt.Print(nums, " ") + total := 0 + for _, num := range nums { + total += num + } + fmt.Println(total) +} + +func main() { + + // Variadic functions can be called in the usual way + sum(1, 2) + sum(1, 2, 3) + + // apply multiple args to a variadic function + nums := []int{1, 2, 3, 4} + sum(nums...) +} diff --git a/5-go-by-example/15-closures.go b/5-go-by-example/15-closures.go new file mode 100644 index 0000000..a97ee4d --- /dev/null +++ b/5-go-by-example/15-closures.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +// Go supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it. + +// intSeq returns another function, which is defined anonymously in the body of intSeq +// the returned function closes over the variable i to form a closure +func intSeq() func() int { + i := 0 + return func() int { + i++ + return i + } +} + +func main() { + // call intSeq, assigning the result (a function) to nextInt + nextInt := intSeq() + + // see the effect of the closure + fmt.Println(nextInt()) + fmt.Println(nextInt()) + fmt.Println(nextInt()) + + // confirm that the state is unique to that particular function + newInts := intSeq() + fmt.Println(newInts()) +} diff --git a/5-go-by-example/16-recursion.go b/5-go-by-example/16-recursion.go new file mode 100644 index 0000000..7a3914e --- /dev/null +++ b/5-go-by-example/16-recursion.go @@ -0,0 +1,29 @@ +package main + +import "fmt" + +// fact function calls itself until it reaches the base case of fact(0) +func fact(n int) int { + if n == 0 { + return 1 + } + return n * fact(n-1) +} + +func main() { + fmt.Println(fact(7)) + + // Closures can also be recursive, but this requires the closure to be declared with a typed var explicitly before it’s defined + var fib func(n int) int + + // Go knows which function to call with fib as it is defined previously in main + fib = func(n int) int { + if n < 2 { + return n + } + return fib(n-1) + fib(n-2) + + } + + fmt.Println(fib(7)) +} diff --git a/5-go-by-example/17-pointers.go b/5-go-by-example/17-pointers.go new file mode 100644 index 0000000..0a2c440 --- /dev/null +++ b/5-go-by-example/17-pointers.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +// Go supports pointers, allowing you to pass references to values and records within your program + +// zeroval has an int parameter, so arguments will be passed to it by value +// zeroval will get a copy of ival distinct from the one in the calling function +func zeroval(ival int) { + ival = 0 +} + +// zeroptr has an *int parameter, meaning that it takes an int pointer +// the *iptr code in the function body then dereferences the pointer from its memory address to the current value at that address +// assigning a value to a dereferenced pointer changes the value at the referenced address +func zeroptr(iptr *int) { + *iptr = 0 +} + +func main() { + i := 1 + fmt.Println("initial:", i) + + zeroval(i) + fmt.Println("zeroval:", i) + + // &i syntax gives the memory address + zeroptr(&i) + fmt.Println("zeroptr:", i) + + // Pointers can be printed + fmt.Println("pointer:", &i) +} diff --git a/5-go-by-example/18-structs.go b/5-go-by-example/18-structs.go new file mode 100644 index 0000000..691ebce --- /dev/null +++ b/5-go-by-example/18-structs.go @@ -0,0 +1,49 @@ +package main + +import "fmt" + +// Go’s structs are typed collections of fields. They’re useful for grouping data together to form records. + +// this person struct type has name and age fields +type person struct { + name string + age int +} + +// newPerson constructs a new person struct with the given name +// safely return a pointer to local variable as a local variable will survive the scope of the function +func newPerson(name string) *person { + p := person{name: name} + p.age = 42 + return &p +} + +func main() { + // create a new struct + fmt.Println(person{"Bob", 20}) + + // name the fields when initializing a struct + fmt.Println(person{name: "Alice", age: 30}) + + // omitted fields will be zero-valued + fmt.Println(person{name: "Fred"}) + + // & prefix yields a pointer to the struct + fmt.Println(&person{name: "Ann", age: 40}) + + // encapsulate new struct creation in constructor functions (ideomatic) + fmt.Println(newPerson("Jon")) + + // access struct fields with a dot + s := person{name: "Sean", age: 50} + fmt.Println(s.name) + + // use dots with struct pointers + // the pointers are automatically dereferenced + sp := &s + fmt.Println(sp.age) + + // structs are mutable + sp.age = 51 + fmt.Println(sp.age) +} diff --git a/5-go-by-example/19-methods.go b/5-go-by-example/19-methods.go new file mode 100644 index 0000000..6137fc5 --- /dev/null +++ b/5-go-by-example/19-methods.go @@ -0,0 +1,32 @@ +// methods defined on struct types + +package main + +import "fmt" + +type rect struct { + width, height int +} + +// area method has a receiver type of *rect +func (r *rect) area() int { + return r.width * r.height +} + +// Methods can be defined for either pointer or value receiver types +func (r rect) perim() int { + return 2*r.width + 2*r.height +} + +func main() { + r := rect{width: 10, height: 5} + + // call 2 methods defined for the struct + fmt.Println("area: ", r.area()) + fmt.Println("perim:", r.perim()) + + // Go automatically handles conversion between values and pointers for method calls + rp := &r + fmt.Println("area: ", rp.area()) + fmt.Println("perim:", rp.perim()) +} diff --git a/5-go-by-example/20-interfaces.go b/5-go-by-example/20-interfaces.go new file mode 100644 index 0000000..110e1bb --- /dev/null +++ b/5-go-by-example/20-interfaces.go @@ -0,0 +1,55 @@ +// Interfaces are named collections of method signatures + +package main + +import ( + "fmt" + "math" +) + +// basic interface for geometric shapes +type geometry interface { + area() float64 + perim() float64 +} + +// implement interface on rect and circle types +type rect struct { + width, height float64 +} +type circle struct { + radius float64 +} + +// implement geometry on rects +func (r rect) area() float64 { + return r.width * r.height +} +func (r rect) perim() float64 { + return 2*r.width + 2*r.height +} + +// implementation for circles +func (c circle) area() float64 { + return math.Pi * c.radius * c.radius +} +func (c circle) perim() float64 { + return 2 * math.Pi * c.radius +} + +// call methods that are in the named interface +func measure(g geometry) { + fmt.Println(g) + fmt.Println(g.area()) + fmt.Println(g.perim()) +} + +func main() { + r := rect{width: 3, height: 4} + c := circle{radius: 5} + + // circle and rect struct types both implement the geometry interface + // use instances of these structs as arguments to measure + measure(r) + measure(c) +}