jayjayswal
12/2/2019 - 3:04 AM

Go in Hour

2. Basics
    basics of the language
    Declaring variables, calling functions
// ---------------------------------------
2.1 Packages, variables, and functions.
// ---------------------------------------
basic components of any Go program.

program
    contains * packages
    - start running in package main.


package main

// multiple import statements
import "fmt"
import "math"

OR

// factored import statement (Good)
import (
	"fmt"               // import path
	"math/rand"         // import path - contains files that begin with the statement       package rand.
)

// we can refer to the names a package exports, after importing it
// In Go, a name is exported if it begins with a capital letter.
//      Foo is an exported name, as is FOO.     math.Pi     // 3.141592653589793
//      The name foo is not exported.           math.pi     // undefined: math.pi, cannot refer to unexported name math.pi

http://golang.org/pkg/math/rand/#Seed
    seed the number generator



x int;

func add(x int, y int) int;
func add(x, y int) int;  // shortened notation since same types
func add(x, y int) (int, int) {
	return y, x             // return any number of results
}
func split(sum int) (x, y int) {        // return values may be named, used to document the meaning of the return values
	x = sum * 4 / 9     // used to document the meaning of the return values
	y = sum - x         // used to document the meaning of the return values
	return          // "naked" return - should be used only in short functions, as with the example shown here. They can harm readability in longer functions.
}


var c, python, java bool        // package level variables
func main() {
	var i int                   // function level variables
	fmt.Println(i, c, python, java)
}


var str3 string = "hello"   // var declaration with initializer, one per variable.
var n3 int = 1              // var declaration with initializer, one per variable.

var i, j int = 1, 2
var c, python, java = true, false, "no!"        // type can be omitted, if initializer is present

// var str1 string,  n1 int // unexpected comma, expecting semicolon or newline
// var str2 string = "hello",  n2 int = 1 // unexpected comma, expecting semicolon or newline


// Short variable declarations
//  Outside a function,
//          every statement begins with a keyword (var, func, and so on) and
//              so the := construct is not available.
//  Inside a function,
//          the := short assignment statement can be used in place of a     var declaration with implicit type.

	var i, j int = 1, 2                         // var, type initializer
    var c, python, java = true, false, "no!"    // var, initializer
    
	k := 3                                  // initializer      // := short assignment => var declaration with implicit type
	c, python, java := true, false, "no!"   // initializer      // := short assignment => var declaration with implicit type




Basic types
        bool

        string

        int  int8  int16  int32  int64
        uint uint8 uint16 uint32 uint64 uintptr

        byte // alias for uint8

        rune // alias for int32
             // represents a Unicode code point

        float32 float64

        complex64 complex128



var (           // factored var statement
	ToBe   bool       = false
	MaxInt uint64     = 1<<64 - 1
	z      complex128 = cmplx.Sqrt(-5 + 12i)
)


Variables declared without an explicit initial value are given their zero value.
The zero value is:
    0 for numeric types,
    false the boolean type, and
    "" (the empty string) for strings.


Type conversions
    The expression T(v) converts the value v to the type T.
    
        var f2 float64 = 5   // explicit conversion
        var u2 uint = f2    // cannot use f2 (type float64) as type uint in assignment
        ----


        var i int = 42
        var f float64 = float64(i)  // explicit conversion
        var u uint = uint(f)        // explicit conversion
        OR
        i := 42
        f := float64(i)             // explicit conversion
        u := uint(f)                // explicit conversion


Type inferEnce

    // untyped numeric constant assignment - depends on the precision of the constant    
    i := 42           // int
    f := 3.142        // float64
    g := 0.867 + 0.5i // complex128

    // typed assignment
    var i int
    j := i            // j is an int


    v := 42 // change me!                   // int -> 2 mill max,       // later overflows int
    fmt.Printf("v is of type %T\n", v)
    v := 2.5 * 1000000000000000000000       // float64 -> mill bill max
    fmt.Printf("v is of type %T\n", v)
    v := 10000000000000000000000.5 + 10000000000000000000000i // change me!
    fmt.Printf("v is of type %T\n", v)       // float64 + float64 i  -> mill bill max  +  mill bill max  i


Constants
    //  const keyword
    //  for     character, string, boolean, or numeric values
    
    //  no var, no type    so   no := syntax.
    
	const ch = 'c'
	const World = "??"
	const Truth = true
    const Pi = 3.14
    
	fmt.Println("Happy", ch, "Day")     // Happy 99 Day
	fmt.Println("Happy", Pi, "Day")     // Happy 3.14 Day
	fmt.Println("Hello", World)         // Hello ??
	fmt.Println("Go rules?", Truth)     // Go rules? true

Numeric Constants
    // high-precision values
    
    const (
        Small = 1 << 1
        Big   = 1 << 10
    )

// ---------------------------------------
// 2.2 Flow control statements: for, if, else, switch and defer
// ---------------------------------------

Control the flow of your code with conditionals, loops, switches and defers.

	sum := 0
	for i := 0; i < 10; i++ {       //  for loop is only one looping construct
                                    //  for is same as in C/ Java, no more (), but has {}
		sum += i
	}
    
    
    for ; sum < 1000; {     // pre & post conditions can be empty
		sum += sum
	}

    for sum < 1000 {        // pre & post conditions can be empty, without semicolons (C lang while)
		sum += sum
	}
    for {    // oop condition
    }


    
    if x < 0 {      //  for is same as in C/ Java, no more (), but has {}
    }
    
    if v := math.Pow(x, n); v < lim {       // short statement, to execute, before the condition -- if similar to for
		return v
	} else {   // ??? else has to be, on this line only, i.e. ending brace of if ???
        return v + 1                        // variable from if short statement - available
    }
    
    // variable from if short statement - not available

                package main

                import (
                    "fmt"
                )

                func Sqrt(x float64) float64 {
                    prev := 1.0
                    z := 1.0
                    for ; z < 10; z++ {
                        // t := z*z - x
                        z = z - ((z*z - x) / 2 * z)
                        if (z - prev) < 1 {
                            break
                        }
                    }
                    return z
                }

                func main() {
                    fmt.Println(Sqrt(2))
                }


	switch os := runtime.GOOS; os {             // declaratioin & initialization;   condition
	case "darwin":
		fmt.Println("OS X.")                    // break; is automatic
	case "linux":
		fmt.Println("Linux.")
        fallthrough                             // fallthrough to the next default
	default:
		// freebsd, openbsd,
		// plan9, windows...
		fmt.Printf("%s.", os)
	}


	today := time.Now().Weekday()
	switch time.Saturday {
	case today + 0:
		fmt.Println("Today.")
	case today + 1:
		fmt.Println("Tomorrow.")
	case today + 2:
		fmt.Println("In two days.")
	default:
		fmt.Println("Too far away.")
	}


    switch i {
    case 0:
    case f():               // if not 0, then f() will be evaluated for a number (/numeral?)
    }

    // switch true {            // clean way to write long if-then-else chains
    switch {                    // clean way to write long if-then-else chains
	case t.Hour() < 12:
		fmt.Println("Good morning!")
	case t.Hour() < 17:
		fmt.Println("Good afternoon.")
	default:
		fmt.Println("Good evening.")
	}

	fmt.Println("1")
	fmt.Println("2")
    
	defer fmt.Println("world")      // deferred call's arguments are evaluated immediately,
                                    //      but function call is executed after surrounding function (its parent) returns.
	fmt.Println("hello")
	fmt.Println("3")
	fmt.Println("4")
                //  1
                //  2
                //  hello
                //  3
                //  4
                //  world

    package main
    import "fmt"

    func main() {
        fmt.Println("counting")

        for i := 0; i < 10; i++ {
            defer fmt.Println(i)    // Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in LIFO order.
        }

        fmt.Println("done")
    }
                //  counting
                //  done
                //  9
                //  8
                //  7
                //  6
                //  5
                //  4
                //  3
                //  2
                //  1
                //  0



//  More types: structs, slices, and maps.
//      define types based on existing ones: structs, arrays, slices, and maps

Pointers
                        // A pointer holds the memory address of a variable.
    var p1 *int         //      zero value is nil (not NULL)
	fmt.Println(*p2)	//      panic: runtime error: invalid memory address or nil pointer dereference    [signal 0xb code=0xffffffff addr=0x0 pc=0x203f8]
    
    //  var p2 *int     // Error: p2 declared and not used

    i := 42
    p = &i              // p is     pointer to its operand (&)    i.e;   i

    fmt.Println(*p)     // read i through the pointer p     // pointer's underlying value   (*) // "dereferencing" or "indirecting
    *p = 21             // set i through the pointer p

    p = p + 1           // invalid operation: p + 1 (mismatched types *int and int)     // Unlike C, Go has no pointer arithmetic.


Structs
    A struct is a collection of fields.

    type Vertex struct {            // type (instead of var),   struct (instead of int)   comparing to     var i int
        X int
        Y int
    }    

   	v := Vertex{1, 2}               // struct variable (v) creation
	v.X = 4                         // . to access fields
	fmt.Println(v.X)
    
	fmt.Println(Vertex{1, 2})
    
	p := &v
	p.X = 1e9                       // indirection through the pointer is transparent.      // *p.X / p->X is not required



Struct Literals

    type Vertex struct {            // struct with X & Y
        X, Y int
    }

    var (
        v1 = Vertex{1, 2}           // Struct Literal since value are listed. Has type Vertex, X is 1 & Y is 2
        
        v21 = Vertex{X: 1}          // X is 1, and Y:0 is implicit      // using "Name:" syntax for X,   Y defaults to 0  i.e. Y: 0   (JSON-like or JavaScript object notation)
        v22 = Vertex{Y: 2}          // Y is 2, and X:0 is implicit      // using same "Name:" syntax for only Y
        v23 = Vertex{Y: 2, X: 1}    // X is 1, Y is 2, order is not relevant
        
        v3 = Vertex{}               // => X:0 and Y:0
        p  = &Vertex{1, 2}          // has type *Vertex (pointer to the struct value).    pX, p.Y gives values 1, 2
    )

Arrays
    // type [n]T is an array of n values of type T.

	var a [2]string                 // array of 2 sting values
                                    // An array's length is part of its type, so arrays cannot be resized. Better ways exist
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])         // Hello World
	fmt.Println(a)                  // [Hello World]

	for i := 0; i < len(a); i++ {
		fmt.Printf("%s\n", a[i])
	}
                                    // Hello
                                    // World
    
Slices
    //      []T is a slice with elements of type T.
    //      resembles the JavaScript/ Python langs

	s := []int{100, 101, 102, 103, 104}
	fmt.Println(s)      //  [100 101 102 103 104]

Slicing slices
	fmt.Println(s[1:4]) // low index is 1, high index is 4, so slice is from 1 (low index) to 3 (high index-1)      [101 102 103]
    fmt.Println(s[1:1]) // low index is 1, high index is 1, so slice is from 1 (low index) to 0 (high index-1)      []  // empty array
	fmt.Println(s[:4])  // low index is missing, so it implies 0            [100 101 102 103]
	fmt.Println(s[1:])  // high index is missing, so it implies len(s)      [101 102 103 104]
	fmt.Println(s[:])   // both index is missing, so it implies 0 to len(s)     [100 101 102 103 104]


Making slices
<<< somewhat difficult to understand >>>

    // make ([]T, length, capacity)
    
    b := make([]int, 0, 5)  // len(b)=0, cap(b)=5           // make has len (& cap) that can be mentioned
    b = b[:cap(b)]          // len(b)=5, cap(b)=5           // slice will set len
    b = b[1:]               // len(b)=4, cap(b)=4           // slice will set len

    
    // make (..., length, capacity)

    a := make([]int, 5)     // len(a)=5        make a slice of array of ints, 5 count      // ??? zeroed array ??? possibly slice
    printSlice("a", a)      // a len=5 cap=5 [0 0 0 0 0]    
	b := make([]int, 0, 5)
	printSlice("b", b)      // b len=0 cap=5 []
	c := b[:2]
	printSlice("c", c)      // c len=2 cap=5 [0 0]
	d := c[2:5]             // ??? REALLY ???   d is somehow referencing a ?
	printSlice("d", d)      // d len=3 cap=3 [0 0 0]

        func printSlice(s string, x []int) {
            fmt.Printf("%s len=%d cap=%d %v\n",
                s, len(x), cap(x), x)
        }

Making slices from Arrays
(NOTE: THIS IS OBSERVATION ONLY ??? IT WORKS)
	a := [5]int{1, 2, 3, 4, 5}
	fmt.Println(a)      // [1 2 3, 5]
	fmt.Println(a[1:3]) // [2 3]

Nil slices
    var z []int                         // Nil slice        // length & capacity 0      // zero value of a slice is nil
    fmt.Println(z, len(z), cap(z))      // [] 0 0
	if z == nil {                       // condition is true
		fmt.Println("nil!")             // nil!
	}

Adding elements to a slice
    // func append(s []T, vs ...T) []T
    // slice2 = append(slice1, val1, val2, ... )       // in simple

	var a []int             // nil slice
	printSlice("a", a)      // a len=0 cap=0 []
    
	a = append(a, 0)        // add 1 element
	printSlice("a", a)      // a len=1 cap=2 [0]        // slice capacity grew to 2

	a = append(a, 1, 2)     // add 2 elements
	printSlice("a", a)      // a len=3 cap=4 [0 1 2]    // slice capacity grew to 4

	a = append(a, 2, 3, 4)  // add multiple elements
	printSlice("a", a)      // a len=5 cap=8 [0 1 2 3 4]    // slice capacity grew to 8

	a = append(a, 5, 6, 7, 8)   // add multiple elements
	printSlice("a", a)      // a len=9 cap=16 [0 1 2 3 4 5 6 7 8]   // slice capacity grew to 16
	
	a = append(a, 9, 10, 11, 12, 13, 14, 15, 16)
	printSlice("a", a)      // a len=17 cap=32 [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]   // slice capacity grew to 32

??????????
    capacity increase by power of 2? is this certain
    
???????????
    How about?
        // slice3 = append(slice1, slice2)          // in simple
    How about?
        // slice3 = append(slice1, [2 to 10])       // in simple

Range
    //  range form of the for loop, iterates, over a slice or map
    
	var a = []int{100, 101, 102, 103, 104}
	for i, v := range a {                   //  range returns (index, value) combinations for each element in array
		fmt.Printf("%d %d\n", i, v)
	}
                                // 0 100
                                // 1 101
                                // 2 102
                                // 3 103
                                // 4 104

    var powers_of_two = []int{1, 2, 4, 8, 16, 32, 64, 128}
	for i, v := range powers_of_two {              //  range returns, (index, value i.e. array[index]) combinations, for each element in array
		fmt.Printf("2 power %d = %d\n", i, v)
	}
                                //  2 power 0 = 1
                                //  2 power 1 = 2
                                //  2 power 2 = 4
                                //  2 power 3 = 8
                                //  2 power 4 = 16
                                //  2 power 5 = 32
                                //  2 power 6 = 64
                                //  2 power 7 = 128
    
	for _, v := range powers_of_two {               // index is dropped, only value is considered
		fmt.Printf("2 power wHaT = %d\n", v)
	}
                                //  2 power wHaT = 1
                                //  2 power wHaT = 2
                                //  2 power wHaT = 4
                                //  2 power wHaT = 8
                                //  2 power wHaT = 16
                                //  2 power wHaT = 32
                                //  2 power wHaT = 64
                                //  2 power wHaT = 128

	for i := range powers_of_two {                      // only index, value is dropped
		fmt.Printf("2 power %d = wHaT\n", i)
	}
                                //  2 power 0 = wHaT
                                //  2 power 1 = wHaT
                                //  2 power 2 = wHaT
                                //  2 power 3 = wHaT
                                //  2 power 4 = wHaT
                                //  2 power 5 = wHaT
                                //  2 power 6 = wHaT
                                //  2 power 7 = wHaT


Maps
    //// make ([]T, length, capacity)
    // make (map[T1] T2)

	// CHECK
	var mapDayNum map[string]int        // map   maps    keys to values
	mapDayNum = make(map[string]int)    // created with   make (not new)   before use
	mapDayNum["Sun"] = 0
	mapDayNum["Mon"] = 1
	mapDayNum["Tue"] = 2
	mapDayNum["Wed"] = 3
	mapDayNum["Thr"] = 4
	mapDayNum["Fri"] = 5
	mapDayNum["Sat"] = 6
	fmt.Println(mapDayNum["Fri"])

	type Vertex struct {
		Lat, Long float64
	}
	m := make(map[string]Vertex)        // short assignment - declaration & creation
	m["Bell Labs"] = Vertex{40.68433, -74.39967}
	fmt.Println(m["Bell Labs"])

    var mapDayNum_2 map[string]int      // map   maps    keys to values
	mapDayNum_2["Sun"] = 0 // panic: assignment to entry in nil map     // the nil map is empty and cannot be assigned to.


Map literals
    // similar to struct literals
    
    type Vertex struct {
        Lat, Long float64
    }

    var m = map[string]Vertex{
        "Bell Labs": Vertex{40.68433, -74.39967},   // A map literals - both key & value is required
        "Google": Vertex{
            37.42202, -122.08408,               // Note: Comma is must here since composite literal --- else --- missing ',' before newline in composite literal
        },
        "Bell Labs 2": {42.68433, -74.39967},   // Note: Comma is must here too since composite literal --- Note: type Vertex omitted --- omit type name from the elements of the literal, if the ??? top-level type ??? is just a type name
    }

    fmt.Println(m["Google"])        // {37.42202 -122.08408}
    fmt.Println(m)                  // map[Bell Labs 2:{42.68433 -74.39967} Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
                                    // ?????? Note element order in map, is not preserved ???????

Mutating Maps

	m := make(map[string]int)

	m["Answer"] = 100        // insert operation
	fmt.Println(m["Answer"]) // 100     << retrieve operatioin >>

	m["Answer"] = 101        // update
	fmt.Println(m["Answer"]) // 101     << retrieve operatioin >>

	var v int
	v = m["Answer"] // retrieve --- one-value assignment
	fmt.Println(v)  // 101

	var ok bool
	v, ok = m["Answer"] // retrieve --- two-value assignment
	fmt.Println(v, ok)  // 101 true

	delete(m, "Answer")      // delete "Answer" key (so, its value too)
	fmt.Println(m["Answer"]) // 0

	v, ok = m["Answer"] // retrieve --- two-value assignment
	fmt.Println(v, ok)  // 0 false  ---- really??? (???? so its always safe to check ok to be true, then access value, since our value can be 0 ????)

Function values
    // Functions are values too.

    package main

    import (
        "fmt"
        "math"
    )

    func sum(a int, b int) int { // sum function takes 2 int parameters, returns int
        return (a + b)
    }
    func sum2(a, b int) int { // same as sum, omitted type for a, used shortened paramters notation, since they both are of same type (int)
        return (a + b)
    }

    /*
    shortened paramter notation looks useful for fewer params, not otherwise
    ex:
    func fn1(a, b, c, d int)       {}

    // now, if b is to be made string

    // with mistake as below, now both a & b will become string
    func fn1(a, b string, c, d int) {}  // wrong, both a & b becomes string

    func fn1(b string, a, c, d int) {}  // correct, both b is string, a remains int
    */

    // sum(5); // can't call here only declaration are allowed --- Error --- "non-declaration statement outside function body"

    func main() {
        fmt.Println(sum(3, 4))  // 7  --- here its ok
        fmt.Println(sum2(3, 4)) // 7  --- here its ok

        sum3 := func(a int, b int) int { // Functions are values too.
            return (a + b)
        }
        fmt.Println(sum3(3, 4)) // 7  --- here its ok

        hypot := func(x, y float64) float64 { // Functions are values too.
            return math.Sqrt(x*x + y*y)
        }
        fmt.Println(hypot(3, 4))
    }


Function closures
<< little complicated concept: closure function >>
    Example 1:
        package main

        import "fmt"

        func counter(start int) func() int { // function that    takes int   and     returns    another function and returns int

            cntr := start // create new closure-variable(s)

            return func() int { // returns a new closure-function
                cntr++ // accessing closure variable(s) inside closure function
                // each time this closure-function is called, it's (corresponding) closure variable (cntr) is incremented
                return cntr // its corresponding closure variable is returned
            }
        } // note that call to counter will create a new closure variable & a new closure function

        func main() {
            counter1, counter2 := counter(0), counter(100) // variables assigned to the returned closure-functions which access their own closure-variables (starting from 0 & 100)

            fmt.Println()
            fmt.Println(counter1()) // 1, since counter1 start value is 0
            fmt.Println(counter1()) // 2

            fmt.Println()
            fmt.Println(counter2()) // 101, since counter1 start value is 100
            fmt.Println(counter2()) // 102
        }
    

    Example 2:
        package main

        import "fmt"

        func adder() func(int) int { // function that  returns another function that takes int and returns int
            sum := 0                 // create new closure-variable(s)
            return func(x int) int { // returns a new closure-function
                sum += x // accessing closure variable(s) inside closure function
                // each time this closure-function is called, it's (corresponding) closure variable (sum) is incremented by x
                return sum // its corresponding closure variable is returned
            }
        } // note that call to adder will create a new closure variable & a new closure function

        func main() {
            positiveAdder, negativeAdder := adder(), adder() // positive & negative variables taking values as returned closure-functions, they access their own closure-variables

            fmt.Println();
            for i := 1; i <= 5; i++ {
                fmt.Println(positiveAdder(i))       // 1 3 6 10 15
            }

            fmt.Println();
            for i := 1; i <= 5; i++ {
                fmt.Println(negativeAdder(-i))      // -1 -3 -6 -10 -15
            }
        }


3. Methods and interfaces
    define methods on types
    declare interfaces
    put everything together.

3.1 Methods and interfaces
    methods and interfaces
    constructs that define objects and their behavior.

define methods on types
    
        package main

        import (
            "fmt"
        )

        type Vertex struct { // no classes, just struct(s)
            X, Y float64
        }

        // defining method on struct type, is thru, mentioning a method receiver in its own argument list, between func keyword & method (function) name

        func (v *Vertex) getX() float64 { // method receiver is Vertex, given as (v *Vertex)
            return v.X
        }

        func (v *Vertex) getY() float64 { // method receiver is Vertex, given as (v *Vertex)
            return v.Y
        }

        func main() {
            v := &Vertex{1, 0}
            fmt.Println("Vertex is", v.getX(), v.getY())
        }


define methods on types - continued

        package main

        import (
            "fmt"
        )

        type MyFloat3 struct {
            X float64 // semicolon not needed (only literals have commmas ?)
            Y float64 // semicolon not needed (only literals have commmas ?)
            Z float64 // semicolon not needed (only literals have commmas ?)
        }

        type MyFloat2 struct { // struct with two elements
            X float64
            Y float64
        }

        type MyFloat11 struct { // struct with one elements
            X float64
        }

        // MyFloat12
        type MyFloat1 float64 // (???) struct with one element, omitted " struct, {, }, X "   (???)

        // can declare a method on any type that is declared in your package, not just struct types.
        func (f MyFloat1) reverseSign() float64 { // method (reverseSign) receiver is MyFloat1
            return float64(-f)
        }

        /*
        // cannot define a method on a type from another package (including built in types)
        func (f float64) reverseSign2() float64 { // error  "cannot define new methods on non-local type float64"
            return float64(-f)
        }
        */

        func main() {
            mf1 := MyFloat1(0.1) // creating instance of s
            fmt.Println(mf1.reverseSign())

            mf2 := MyFloat1(-0.1) // creating instance of s
            fmt.Println(mf2.reverseSign())
        }

#3
        package main

        import (
            "fmt"
        )

        type Vertex struct {
            X, Y float64
        }

        func (v *Vertex) getX() float64 { // Vertex is a pointer type/ pointer receiver
            return v.X
            // pointer receiver/ pointer type
            // - copy of (original) value is not created (efficient if big values)
            // - can modify value that pointer receiver points to
        }

        func (v Vertex) getY() float64 { // Vertex is a value type/ value receiver
            return v.Y
            // value receiver/ value type
            // - copy of (original) value  is created/ mutated
            // - can not modify value that pointer receiver points to
        }

        func (v *Vertex) setX(f1 float64) { // Vertex is a pointer type/ pointer receiver
            v.X = f1
            // pointer receiver/ pointer type
            // - copy of (original) value is not created (efficient if big values)
            // - can not modify value that pointer receiver points to
        }

        func (v Vertex) setY(f1 float64) { // Vertex is a value type/ value receiver
            v.Y = f1
            // value receiver/ value type
            // - copy of (original) value  is created/ mutated
            // - can not modify value that pointer receiver points to
        }

        func main() {
            v := &Vertex{1, 0}
            fmt.Println("Vertex is", v.getX(), v.getY())  // Vertex is 1 0

            f1, f2 := 101.0, 100.0
            v.setX(f1)
            v.setY(f2)

            fmt.Println("Vertex is", v.getX(), v.getY())  // Vertex is 101 0
        }


Interfaces
-- An interface type    is      a set of methods.
-- A value of interface type    can hold    any value   that implements     those methods.

#1
        package main

        import (
            "fmt"
            "math"
        )

        type Abser interface { // interface type
            Abs() float64 //  set of methods.
        }

        type MyFloat float64

        func (f MyFloat) Abs() float64 { // MyFloat now implements Abser interface by implementing its functions (Abs) --- Note: Name interface name (Abser) is not used
            if f < 0 {
                return float64(-f)
            }
            return float64(f)
        }

        type Vertex struct {
            X, Y float64
        }

        func (v *Vertex) Abs() float64 { // *Vertex now implements Abser interface by implementing its functions (Abs) --- Note: Name interface name (Abser) is not used
            return math.Sqrt(v.X*v.X + v.Y*v.Y)
        }

        func main() {
            var a Abser
            f := MyFloat(-math.Sqrt2)
            v := Vertex{3, 4}

            a = f // a MyFloat implements Abser
            fmt.Println(a.Abs())

            a = &v // a *Vertex implements Abser
            fmt.Println(a.Abs())

            // Below link errors with: "Vertex does not implement Abser (Abs method has pointer receiver)"

            // a = v // a Vertex (not *Vertex) does not implement Abser.
            // fmt.Println(a.Abs())
        }


#2
        package main

        import (
            "fmt"
            "os"
        )

        // Interfaces are satisfied implicitly

        // A type   implements   an interface   by implementing the methods.
        //    no "implements" keyword (there is no explicit declaration of intent)

        // Implicit interfaces decouple
        //    implementation packages (??? where the interfaces are implemented ???) from
        //    the packages that define the interfaces (??? where the interface is declared ???)
        //        neither depends on the other.

        // It also encourages the definition of precise interfaces,
        //    because
        //       you don't have to find every implementation and
        //           tag it with the new interface name.
        //                  ??? Note: Name interface name (Abser) is not used, while implememting interface by Vertex ???


        type Reader interface {
            Read(b []byte) (n int, err error)
        }

        type Writer interface {
            Write(b []byte) (n int, err error)
        }

        type ReadWriter interface {
            Reader
            Writer
        }
        
        // Package io defines Reader and Writer; you don't have to.

        func main() {
            fmt.Fprintf(os.Stdout, "hello, writer\n")  // hello, writer
            
            var w Writer
            // os.Stdout implements Writer
            w = os.Stdout
            fmt.Fprintf(w, "hello, writer\n")  // hello, writer
        }


Stringers

    One of the most ubiquitous interfaces is Stringer defined by the fmt package.

    type Stringer interface {
        String() string
    }
    A Stringer is a type that can describe itself as a string.
    The fmt package (and many others) look for this interface to print values.

        package main

        import "fmt"

        type Person struct {
            Name string
            Age  int
        }

        func (p Person) String() string {
            return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
        }

        func main() {
            a := Person{"Arthur Dent", 42}
            z := Person{"Zaphod Beeblebrox", 9001}
            fmt.Println(a, z)       // Stringer used        --- Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
        }

Errors
Go programs     express error state     with error values.

    The     error   type is a built-in interface,    similar to fmt.Stringer:

    type error interface {
        Error() string
    }
    (As with fmt.Stringer, the fmt package looks for the error interface when printing values.)

    i, err := strconv.Atoi("42")
    if err != nil {                                         // test if error
        fmt.Printf("couldn't convert number: %v\n", err)    // handle error
        return                                              // ??????????? missing return - looks like error ????????????
    }
    fmt.Println("Converted integer:", i)
    A nil error denotes success; a non-nil error denotes failure.

#1
        package main

        import (
            "fmt"
            "time"
        )

        type MyError struct {
            When time.Time
            What string
        }

        func (e *MyError) Error() string { // MyError structure implements error interface, by implementng Error() function
            return fmt.Sprintf("at %v: %s", e.When, e.What)
        }

        func run(n int) (int, error) {
            //  ...
            if n == 0 {
                return 0, &MyError{time.Now(), "its an invalid value"}
            } else {
                return n, nil
            }
        }

        func main() {
            i := 0
            if n, err := run(i); err != nil {
                fmt.Println("Error:", err)      // --- i := 0 ---  Error: at 2009-11-10 23:00:00 +0000 UTC: its an invalid value
            } else {
                fmt.Println("Value:", n)        // --- i := 1 --- Value: 1
            }
        }


https://tour.golang.org/methods/10


The io package
    specifies
        the io.Reader interface,
            which represents the    read end     of a stream of data.

io interfaces
    files,
    network connections,
    compressors,
    ciphers, and
    others.

io.Reader
        type Reader interface {
             Read(p []byte) (n int, err error)
        }

            Read
                populates the given byte slice
                with data and
                returns
                    the number of bytes populated and
                    an error value.
                        It returns an io.EOF error when the stream ends.

#1
        package main

        import (
            "fmt"
            "io"
            "strings"       // implements io.Reader
        )

        func main() {
            r := strings.NewReader("Hello, Reader!")    // get a new Reader instance, with string as input

            b := make([]byte, 8)                        // create a byte slice of length 8
            for {
                n, err := r.Read(b)                     // read from string input, into byte slice (8 bytes at a time)
                fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
                fmt.Printf("b[:n] = %q\n", b[:n])
                if err == io.EOF {
                    break
                }
            }
        }

                //                      n = 8 err = <nil> b = [72 101 108 108 111 44 32 82]
                //                      b[:n] = "Hello, R"
                //                      n = 6 err = <nil> b = [101 97 100 101 114 33 32 82]
                //                      b[:n] = "eader!"
                //                      n = 0 err = EOF b = [101 97 100 101 114 33 32 82]
                //                      b[:n] = ""



Web servers
    Package http    serves HTTP requests     using any value that implements http.Handler:

    package http

    type Handler interface {
        ServeHTTP(w ResponseWriter, r *Request)
    }

#1
        package main

        import (
            "fmt"
            "log"
            "net/http"
        )

        type Hello struct{}

        func (h Hello) ServeHTTP( // type Hello implements http.Handler
            w http.ResponseWriter,
            r *http.Request,
        ) {

            fmt.Fprint(w, "Hello!")
        }

        func main() {
            var h Hello
            err := http.ListenAndServe("localhost:4000", h)
            if err != nil {
                log.Fatal(err)
            }
            // Visit http://localhost:4000/ to see the greeting.

        }

        
Images
        
#1
        package main

        import (
            "fmt"
            "image"
        )

        func main() {
            m := image.NewRGBA(image.Rect(0, 0, 100, 100))
            fmt.Println(m.Bounds())
            fmt.Println(m.At(0, 0).RGBA())
        }
//            (0,0)-(100,100)
//            0 0 0 0


#4
Concurrency
    Go provides     concurrency features/constructions    as part of the      core language.
    This module goes over
        goroutines and
        channels, and
        how they are used
            to implement
            different concurrency patterns.

        presents them and
        gives some examples on how to use it.

        

Channels
    Channels are a typed conduit through which you can send and receive values with the channel operator, <-.
    
    #Ex1
            package main

            import (
                "fmt"
                "time"
            )

            func say(s string) {
                for i := 0; i < 5; i++ {
                    time.Sleep(100 * time.Millisecond)
                    fmt.Println(s)
                }
            }

            func main() {
                go say("world") // starts a new goroutine to run say // A goroutine is a       lightweight thread     managed by the     Go runtime.
                // evaluation is done in current goroutine, and
                //	execution happens in the new goroutine, but in same address space, so access to shared memory must be synchronized, ex: using sync package, etc.

                say("hello") //  run say
            }

        #Ex 2
            package main

            import "fmt"

            func sum(a []int, c chan int) { // run by each goroutine
                sum := 0
                for _, v := range a {
                    sum += v
                }
                c <- sum // goroutine sends its sum to channel c using channel operator, <-
            }

            func main() {
                a := []int{7, 2, 8, -9, 4, 0} // shared memory

                c := make(chan int) // channel c is created, similar to slices & maps

                // sums 1st half of array
                go sum(a[:len(a)/2], c) // starts goroutine/lightweight thread, synchronizes using same channel (without explicit locks or condition variables)

                // sums 2nd half of array
                go sum(a[len(a)/2:], c) // starts goroutine/lightweight thread, synchronizes using same channel (without explicit locks or condition variables)

                // both half sums of array are collected
                x, y := <-c, <-c // receive from channel c (from lightweight threads) using channel operator, <-

                // total sum of array is printed
                fmt.Println(x, y, x+y)      // 17 -5 12
            }


Buffered Channels       ?????????? Why to use Buffered? to make sure our programs are correct as expected - to catch bugs at dev.t ????????
    Channels can be buffered. Provide the buffer length as the second argument to initialize a buffered channel:

    ch := make(chan int, 100)
    Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty. ????? what ????? 

    Modify the example to overfill the buffer and see what happens.

            package main

            import "fmt"

            func main() {
                // Channels can be buffered
                ch := make(chan int, 2) // create a buffered channel of buffer length 2

                ch <- 1 // uses part of length of buffer
                ch <- 2 // uses part of length of buffer

                // if overfill (buffer length is not enough)
                // error --- fatal error: all goroutines are asleep - deadlock!

                // if underfill (buffer length is not enough)

                fmt.Println(<-ch)
                fmt.Println(<-ch) // if (less channels created than asked)
                // error --- fatal error: all goroutines are asleep - deadlock!

            }

Range and Close - on Channel

            #Ex: 1
            package main

            import (
                "fmt"
            )

            func fibonacci(n int, c chan int) {
                x, y := 0, 1
                for i := 0; i < n; i++ {
                    c <- x
                    x, y = y, x+y // ??? right side values are evaluated, then are assigned ???
                }
                close(c) // sender closes channel --- no more values will be sent
                            --- not required in general, required only to terminate a range loop at reciever's end

                // c <- 1 // Sending on a closed channel will cause a panic.
            }

            func main() {
                c := make(chan int, 10)
                go fibonacci(cap(c), c)
                // 	in a general for loop
                //		v, ok := <-ch  // ok is false if channel is closed, no more values to receive
                // 	  or
                //	in the for loop wih range
                for i := range c { // receives values from the channel repeatedly until it is closed.
                    fmt.Println(i)
                }
                
                // receiver never closes channel
            }
                // 0
                //  1
                //  1
                //  2
                //  3
                //  5
                //  8
                //  13
                //  21
                //  34

Select
                package main

                import "fmt"

                func fibonacci(c, quit chan int) {
                    x, y := 0, 1
                    for {
                        select {    // goroutine waits/blocks on multiple communication operations - chooses one at random if multiple are ready (really ???)
                        case c <- x: // send to channel new fibonacci num
                            x, y = y, x+y // cal new fibonscci num (into x)
                        case <-quit: // value is recieved from quit channel
                            fmt.Println("quit")
                            return
                        }
                    }
                }

                func main() {
                    c := make(chan int)    // channel is created to communicate ints
                    quit := make(chan int) // another channel is created to communicate quit
                    go func() {            // goroutine (lightweight thread) is created with this function
                        for i := 0; i < 10; i++ {
                            fmt.Println(<-c) // channel sends its recieved data to print
                        }
                        quit <- 0 // 0 is sent to quit channel
                    }() // execute the goroutine
                    fibonacci(c, quit)
                }


Default Selection
                package main

                import (
                    "fmt"
                    "time"
                )

                func main() {
                    tick := time.Tick(100 * time.Millisecond)
                    boom := time.After(500 * time.Millisecond)
                    for {
                        select {
                        case <-tick:
                            fmt.Println("tick.")
                        case <-boom:
                            fmt.Println("BOOM!")
                            return
                        default: // no other case is ready --- to try a send or receive without blocking
                            fmt.Println("    .")
                            time.Sleep(50 * time.Millisecond)

                            // receiving from tick/boom would block
                        }
                    }
                }