Go Lang ======= Notes are of https://tour.golang.org/ Quick Links ----------- + `GO keywords `_ Variables --------- Declared with ``var`` The ``:=`` operator .. code-block:: go package main import "fmt" func main() { fmt.Println("counting") for i := 0; i < 10; i++ { defer fmt.Println(i) } fmt.Println("done") } Pointers ~~~~~~~~ This is mostly the same as C with one exception, there is no pointer arithmetic! The ``&`` operator generates a pointer to its operand. The ``*`` operator denotes the pointer's underlying value. Structs ~~~~~~~ Almost what you think, you just need to prepend ``type struct {}`` .. code-block :: go package main import "fmt" type Vertex struct { X int Y int } func main() { fmt.Println(Vertex{1, 2}) v.X = 4 fmt.Println(v.X) } To access the field X of a struct when we have the struct pointer p we could write ``(*p).X.`` However, that notation is cumbersome, so the language permits us instead to write just ``p.X``, without the explicit dereference. .. code-block :: go p = &v p.X = 1e9 When initializing You can specify a subset of values and the rest will implicitly be set to their default values .. code-block :: go v2 = Vertex{X: 1} // v2.X = 1, v2.Y = 0 Arrays ~~~~~~ .. code-block :: go var a [10]int Slices ~~~~~~ They are syntactic surgar for references to a portion of the underlying array thus do not create copies of the data. Super fast and efficient. .. code-block :: go a[low : high] The zero value of a slice is nil. A nil slice has a length and capacity of 0 and has no underlying array. Slices can be created with the built-in ``make`` function; this is how you create dynamically-sized arrays. Make ++++ The make function allocates a zeroed array and returns a slice that refers to that array: .. code-block :: go a := make([]int, 5) // len(a)=5 // To specify a capacity, pass a third argument to make: b := make([]int, 0, 5) // len(b)=0, cap(b)=5 b = b[:cap(b)] // len(b)=5, cap(b)=5 b = b[1:] // len(b)=4, cap(b)=4 Append ++++++ It is common to append new elements to a slice, and so Go provides a built-in append function. The documentation of the built-in package describes append. ``func append(s []T, vs ...T) []T`` The first parameter s of append is a slice of type T, and the rest are T values to append to the slice. The resulting value of append is a slice containing all the elements of the original slice plus the provided values. If the backing array of s is too small to fit all the given values a bigger array will be allocated. The returned slice will point to the newly allocated array. Range +++++ The range form of the for loop iterates over a slice or map. When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index. .. code-block :: go var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } } Maps ~~~~ .. code-block go package main import "fmt" type Vertex struct { Lat, Long float64 } var m map[string]Vertex func main() { m = make(map[string]Vertex) m["Bell Labs"] = Vertex{ 40.68433, -74.39967, } fmt.Println(m["Bell Labs"]) } **Is there an element in the map?** ``elem, ok = m[key]`` If key is in m, ok is true. If not, ok is false. If key is not in the map, then elem is the zero value for the map's element type. Collections ----------- - Arrays - Slices - Maps Functions --------- They are first class citizens and can be treated as values. Closures ~~~~~~~~ Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is "bound" to the variables. For example, the adder function returns a closure. Each closure is bound to its own sum variable. .. code-block go import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } } Conditionals ------------ Loops and if statements live here! Loops ----- There are no "while" loops in go, and () are not needed in the conditional controlling the loop but {} are need to delimit the end of the loop unlike some languages (Gives a dirty look at Python [jk I love Python :D]) .. code-block:: go //TODO Switch Statements ~~~~~~~~~~~~~~~~~ Switch statements work how you think they do .. code-block:: go func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.\n", os) } } Well actually they're better than you think they are. Switch statements can switch on types.A type switch is like a regular switch statement, but the cases in a type switch specify types (not values), and those values are compared against the type of the value held by the given interface value. .. code-block :: go switch v := i.(type) { case T: // here v has type T case S: // here v has type S default: // no match; here v has the same type as i } Defer ~~~~~ A defer statement defers the execution of a function until the surrounding function returns. The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns. .. code-block :: go package main import "fmt" func main() { defer fmt.Println("world") fmt.Println("hello") } The above code outputs: ``hello\n world`` Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order. To learn more about defer statements read this `blog post `_. Methods ------- Go has no classes, but you can define methods for structs. It's got a wack syntax though using recievers .. code-block :: go type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) } You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int). Pointer Receivers ~~~~~~~~~~~~~~~~~ By default GO is pass by value, so to have a method change the struct it was called on it has to be defined with a pointer receiver. .. code-block :: go func (v *Vertex) Scale {} The above can change struct members Interfaces ---------- An interface type is defined as a set of method signatures. A value of interface type can hold any value that implements those methods. Interfaces are implemented implicitly. A type implements an interface by implementing its methods. There is no explicit declaration of intent, no "implements" keyword. **Less complex Ex** .. code-block :: go package main import "fmt" type I interface { M() } type T struct { S string } // This method means type T implements the interface I, // but we don't need to explicitly declare that it does so. func (t T) M() { fmt.Println(t.S) } func main() { var i I = T{"hello"} i.M() } **More complex** .. code-block :: go package main import ( "fmt" "math" ) type Abser interface { Abs() float64 } func main() { var a Abser f := MyFloat(-math.Sqrt2) v := Vertex{3, 4} a = f // a MyFloat implements Abser a = &v // a *Vertex implements Abser // In the following line, v is a Vertex (not *Vertex) // and does NOT implement Abser. a = v fmt.Println(a.Abs()) } type MyFloat float64 func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } type Vertex struct { X, Y float64 } func (v *Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } Stuff on Type assertion and empty interfaces. How to avoid a panic when using type assertions, Stringers ~~~~~~~~~ One of the most ubiquitous interfaces is Stringer defined by the fmt package. .. code-block :: go 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. Readers ~~~~~~~ The ``io`` package specifies the ``io.Reader`` interface, which represents the read end of a stream of data. The io.Reader interface has a Read method: .. code-block :: go func (T) Read(b []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. Error Propegation ----------------- Errors are handled through the ``error`` interface. .. code-block :: go type error interface { Error() string } Modules ------- Automated testing ----------------- Goroutines ---------- Librarys to Know about ---------------------- - https://golang.org/pkg/ - https://golang.org/pkg/strings/#Fields