Skip to content

Instantly share code, notes, and snippets.

@y-lan
Forked from Integralist/Golang Essentials.md
Created January 28, 2016 04:39

Revisions

  1. @Integralist Integralist revised this gist Jan 27, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@
    - [Spurious](#spurious)
    - [AWS SDK with Go (OLD!)](#aws-sdk-with-go)
    - [Build and Compilation](#build-and-compilation)
    - [Dependencies](#dependencies)
    - [Dependency information with `go list`](#dependency-information-with-go-list)
    - [Dependencies with godeps](#dependencies-with-godeps)
    - [Dependencies with gb](#dependencies-with-gb)
    - [Dependencies with glide](#dependencies-with-glide)
    @@ -550,7 +550,7 @@ Use the `-a` flag when running `go build`.

    In short, if you dont' use `go build -a -v .` then Go won't know if any packages are missing (you can find the gory details [here](https://medium.com/@felixge/why-you-should-use-go-build-a-or-gb-c469157d5c1b#.jf5orcwrj))

    ## Dependencies
    ## Dependency information with `go list`

    To see a list of dependencies for a given Go package you can utilise the `go list` command:

  2. @Integralist Integralist revised this gist Jan 27, 2016. 1 changed file with 121 additions and 0 deletions.
    121 changes: 121 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,7 @@
    - [Spurious](#spurious)
    - [AWS SDK with Go (OLD!)](#aws-sdk-with-go)
    - [Build and Compilation](#build-and-compilation)
    - [Dependencies](#dependencies)
    - [Dependencies with godeps](#dependencies-with-godeps)
    - [Dependencies with gb](#dependencies-with-gb)
    - [Dependencies with glide](#dependencies-with-glide)
    @@ -549,6 +550,126 @@ Use the `-a` flag when running `go build`.

    In short, if you dont' use `go build -a -v .` then Go won't know if any packages are missing (you can find the gory details [here](https://medium.com/@felixge/why-you-should-use-go-build-a-or-gb-c469157d5c1b#.jf5orcwrj))

    ## Dependencies

    To see a list of dependencies for a given Go package you can utilise the `go list` command:

    ```bash
    go list -json strconv
    ```

    Which returns:

    ```json
    {
    "Dir": "/usr/local/Cellar/go/1.5.2/libexec/src/strconv",
    "ImportPath": "strconv",
    "Name": "strconv",
    "Doc": "Package strconv implements conversions to and from string representations of basic data types.",
    "Target": "/usr/local/Cellar/go/1.5.2/libexec/pkg/darwin_amd64/strconv.a",
    "Goroot": true,
    "Standard": true,
    "Root": "/usr/local/Cellar/go/1.5.2/libexec",
    "GoFiles": [
    "atob.go",
    "atof.go",
    "atoi.go",
    "decimal.go",
    "doc.go",
    "extfloat.go",
    "ftoa.go",
    "isprint.go",
    "itoa.go",
    "quote.go"
    ],
    "IgnoredGoFiles": [
    "makeisprint.go"
    ],
    "Imports": [
    "errors",
    "math",
    "unicode/utf8"
    ],
    "Deps": [
    "errors",
    "math",
    "runtime",
    "unicode/utf8",
    "unsafe"
    ],
    "TestGoFiles": [
    "internal_test.go"
    ],
    "XTestGoFiles": [
    "atob_test.go",
    "atof_test.go",
    "atoi_test.go",
    "decimal_test.go",
    "example_test.go",
    "fp_test.go",
    "ftoa_test.go",
    "itoa_test.go",
    "quote_test.go",
    "strconv_test.go"
    ],
    "XTestImports": [
    "bufio",
    "bytes",
    "errors",
    "fmt",
    "log",
    "math",
    "math/rand",
    "os",
    "reflect",
    "runtime",
    "strconv",
    "strings",
    "testing",
    "time",
    "unicode"
    ]
    }
    ```

    If you don't specify the `-json` flag then the default behaviour is to filter out the `ImportPath` field from the above JSON output. For example:

    ```bash
    go list strconv
    ```

    Will return just the import path `strconv`.

    > Documentation: `go help list | less`
    You can also utilise Go's templating functionality on the returned JSON object by adding the `-f` flag:

    ```bash
    go list -f '{{join .Deps " "}}' strconv
    ```

    Which filters out the `Deps` field, joins up all items it contains using whitespace and subsequently returns:

    ```
    errors math runtime unicode/utf8 unsafe
    ```

    You can do more complex things such as:

    ```bash
    go list -f '{{.ImportPath}} -> {{join .Imports " "}}' compress/...
    ```

    Which will return something like:

    ```
    compress/bzip2 -> bufio io sort
    compress/flate -> bufio fmt io math sort strconv
    compress/gzip -> bufio compress/flate errors fmt hash hash/crc32 io time
    compress/lzw -> bufio errors fmt io
    compress/zlib -> bufio compress/flate errors fmt hash hash/adler32 io
    ```

    ## Dependencies with godeps

    When running `go get <dependency>` locally, Go will stick the dependency in the folder defined by your `$GOPATH` variable. So when you build your code into a binary using `go build <script>` it'll bake the dependencies into the binary (i.e. the binary is statically linked).
  3. @Integralist Integralist revised this gist Jan 12, 2016. 1 changed file with 18 additions and 7 deletions.
    25 changes: 18 additions & 7 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,4 @@
    - [Install](#install)
    - [Shell exports](#shell-exports)
    - [Directory explanations](#directory-explanations)
    - [Automatic Imports](#automatic-imports)
    @@ -58,6 +59,12 @@
    - [Enumerator IOTA](#enumerator-iota)
    - [FizzBuzz](#fizzbuzz)

    ## Install

    ```bash
    brew install go
    ```

    ## Shell exports

    - `export GOPATH=~/path/to/your/golang/projects`
    @@ -67,7 +74,17 @@
    ## Directory explanations

    > Make sure you have your project folder inside the following directory structure...
    By default you store all your Golang projects within a single directory. This will be fixed in a future Go release as the developers recognise it can be problematic sometimes.

    So within the `$GOPATH` directory workspace there should be three directories:

    - `src`: holds source code
    - `pkg`: holds compiled bits
    - `bin`: holds executables

    > Note: I very rarely even look at the `pkg` or `bin` directories
    But for now, make sure you have any new Go project you work on placed inside the following directory structure...

    ```
    └── src
    @@ -76,12 +93,6 @@
    │   │   └── <your_repo_name>
    ```

    Within the `$GOPATH` directory workspace there should be three directories:

    - `src`: holds source code
    - `pkg`: holds compiled bits
    - `bin`: holds executables

    ## Automatic Imports

    `go get golang.org/x/tools/cmd/goimports`
  4. @Integralist Integralist revised this gist Jan 10, 2016. 1 changed file with 23 additions and 0 deletions.
    23 changes: 23 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -56,6 +56,7 @@
    - [OAuth](https://gist.github.com/Integralist/0e277a517fee68153f93)
    - [RPC](#rpc)
    - [Enumerator IOTA](#enumerator-iota)
    - [FizzBuzz](#fizzbuzz)

    ## Shell exports

    @@ -3339,4 +3340,26 @@ func main() {
    fmt.Println(foo, bar, baz) // 0 1 3
    fmt.Println(beep, boop) // 0 1
    }
    ```

    ### FizzBuzz

    ```go
    package main

    import "fmt"

    func main() {
    for i := 1; i <= 100; i++ {
    if i%3 == 0 && i%5 == 0 {
    fmt.Printf("%d FizzBuzz\n", i)
    } else if i%3 == 0 {
    fmt.Printf("%d Fizz\n", i)
    } else if i%5 == 0 {
    fmt.Printf("%d Buzz\n", i)
    } else {
    fmt.Println(i)
    }
    }
    }
    ```
  5. @Integralist Integralist revised this gist Dec 31, 2015. 1 changed file with 31 additions and 1 deletion.
    32 changes: 31 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@
    - [Automatic Imports](#automatic-imports)
    - [Private repo access](#private-repo-access)
    - [Guard (automatic go run)](#guard-automatic-go-run)
    - [Godo](#godo)
    - [Spurious](#spurious)
    - [AWS SDK with Go (OLD!)](#aws-sdk-with-go)
    - [Build and Compilation](#build-and-compilation)
    @@ -107,10 +108,39 @@ go get github.com/foo/private

    ## Guard (automatic `go run`)

    **UPDATE**: this isn't good practice. Instead use [Godo](https://github.com/go-godo/godo)
    **UPDATE**: this isn't good practice. Instead use [Godo](https://github.com/go-godo/godo) (see below for example)

    ~~Follow this guide (https://gist.github.com/Integralist/b675a263897680e02fbd) for using Guard to get real-time notifications for when changes occur in your Go programming files, and automatically trigger `go run`.~~

    ## Godo

    Example taken from my own project [go-requester](https://github.com/Integralist/Go-Requester)

    ```go
    package main

    import (
    "fmt"
    "os"

    do "gopkg.in/godo.v2"
    )

    func tasks(p *do.Project) {
    if pwd, err := os.Getwd(); err == nil {
    do.Env = fmt.Sprintf("GOPATH=%s/vendor::$GOPATH", pwd)
    }

    p.Task("server", nil, func(c *do.Context) {
    c.Start("main.go ./config/page.yaml", do.M{"$in": "./"})
    }).Src("**/*.go")
    }

    func main() {
    do.Godo(tasks)
    }
    ```

    ## Spurious

    If you need [Spurious](https://github.com/spurious-io/spurious) set-up then update the `aws.config` accordingly:
  6. @Integralist Integralist revised this gist Dec 31, 2015. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -107,7 +107,9 @@ go get github.com/foo/private

    ## Guard (automatic `go run`)

    Follow this guide (https://gist.github.com/Integralist/b675a263897680e02fbd) for using Guard to get real-time notifications for when changes occur in your Go programming files, and automatically trigger `go run`.
    **UPDATE**: this isn't good practice. Instead use [Godo](https://github.com/go-godo/godo)

    ~~Follow this guide (https://gist.github.com/Integralist/b675a263897680e02fbd) for using Guard to get real-time notifications for when changes occur in your Go programming files, and automatically trigger `go run`.~~

    ## Spurious

  7. @Integralist Integralist revised this gist Dec 31, 2015. 1 changed file with 87 additions and 0 deletions.
    87 changes: 87 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -29,6 +29,7 @@
    - [Read User Input](#read-users-input)
    - [Web Server](#web-server)
    - [Middleware](#middleware)
    - [Sessions](#sessions)
    - [HTTP Requests with Timeouts](#http-requests-with-timeouts)
    - [S3 GetObject](#s3-getobject)
    - [Compile time variables](#compile-time-variables)
    @@ -1649,6 +1650,92 @@ server: middleware.go:38: after
    after
    ```

    ### Sessions

    ```go
    package main

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

    const cookiePrefix = "integralist-example-cookie-"

    func main() {
    http.HandleFunc("/", login)
    http.HandleFunc("/admin", admin)
    http.HandleFunc("/logout", logout)
    http.ListenAndServe("localhost:4000", nil)
    }

    func login(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
    fmt.Fprintf(w, `
    <html>
    <body>
    <form method="POST">
    Username: <input type="text" name="username">
    <br />
    Password: <input type="password" name="password">
    <br />
    <input type="submit" value="Login">
    </body>
    </html>
    `)
    }

    if r.Method == "POST" {
    username := r.FormValue("username")
    password := r.FormValue("password")

    if username == "admin" && password == "password" {
    http.SetCookie(w, &http.Cookie{
    Name: cookiePrefix + "user",
    Value: username,
    })
    http.Redirect(w, r, "/admin", 302)
    } else {
    fmt.Fprintf(w, `
    <html>
    <body>
    Login details were incorrect. Sorry, <a href="/">try again</a>
    </body>
    </html>
    `)
    }
    }
    }

    func logout(w http.ResponseWriter, r *http.Request) {
    http.SetCookie(w, &http.Cookie{
    Name: cookiePrefix + "user",
    Value: "",
    Expires: time.Now(),
    })

    http.Redirect(w, r, "/", 302)
    }

    func admin(w http.ResponseWriter, r *http.Request) {
    cookie, err := r.Cookie(cookiePrefix + "user")
    if err != nil {
    http.Redirect(w, r, "/", 401) // Unauthorized
    return
    }

    fmt.Fprintf(w, `
    <html>
    <body>
    Logged into admin area as: %s<br><br>
    <a href="/logout">Logout</a>
    </body>
    </html>
    `, cookie.Value)
    }
    ```

    ### HTTP Requests with Timeouts

    ```go
  8. @Integralist Integralist revised this gist Dec 30, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -28,6 +28,7 @@
    - [Sorting Structs](#sorting-structs)
    - [Read User Input](#read-users-input)
    - [Web Server](#web-server)
    - [Middleware](#middleware)
    - [HTTP Requests with Timeouts](#http-requests-with-timeouts)
    - [S3 GetObject](#s3-getobject)
    - [Compile time variables](#compile-time-variables)
  9. @Integralist Integralist revised this gist Dec 30, 2015. 1 changed file with 87 additions and 2 deletions.
    89 changes: 87 additions & 2 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -27,7 +27,7 @@
    - [Unknown YAML Structure](#unknown-yaml-structure)
    - [Sorting Structs](#sorting-structs)
    - [Read User Input](#read-users-input)
    - [WebServer](#webserver)
    - [Web Server](#web-server)
    - [HTTP Requests with Timeouts](#http-requests-with-timeouts)
    - [S3 GetObject](#s3-getobject)
    - [Compile time variables](#compile-time-variables)
    @@ -1450,7 +1450,7 @@ text, _ := reader.ReadString('\n')
    fmt.Println(text)
    ```

    ### WebServer
    ### Web Server

    The Go web server design relies on a struct to map routes (URLs) to functions.

    @@ -1563,6 +1563,91 @@ func main() {

    Now visit `http://localhost:4000/string` and `http://localhost:4000/struct` to see the appropriate output

    ### Middleware

    This code was modified from https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81

    ```go
    package main

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

    type data struct {
    Greeting string
    Punct string
    Who string
    }

    func (s data) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, s.Greeting, s.Punct, s.Who)
    }

    type adapter func(http.Handler) http.Handler

    func adapt(h http.Handler, adapters ...adapter) http.Handler {
    // Ideally you'd do this in reverse
    // to ensure the order of the middleware
    // matches their specified order
    for _, adapter := range adapters {
    h = adapter(h)
    }
    return h
    }

    func notify(logger *log.Logger) adapter {
    return func(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    logger.Println("before")
    defer logger.Println("after")
    h.ServeHTTP(w, r)
    })
    }
    }

    func doSomething() adapter {
    return func(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Println("before")
    defer fmt.Println("after")
    h.ServeHTTP(w, r)
    })
    }
    }

    func main() {
    http.Handle("/hello", &data{"Hello", " ", "Gophers!"})

    logger := log.New(os.Stdout, "server: ", log.Lshortfile)

    http.Handle("/hello-with-middleware", adapt(
    &data{"Hello", " ", "Gophers!"},
    notify(logger), // runs second
    doSomething(), // runs first
    ))

    http.ListenAndServe("localhost:4000", nil)
    }
    ```

    This code will run a web server with two valid endpoints:

    1. `/hello`
    2. `/hello-with-middleware`

    The client sees the same output but the latter endpoint produces the following stdout output:

    ```
    before
    server: middleware.go:35: before
    server: middleware.go:38: after
    after
    ```

    ### HTTP Requests with Timeouts

    ```go
  10. @Integralist Integralist revised this gist Dec 30, 2015. 1 changed file with 60 additions and 0 deletions.
    60 changes: 60 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -1381,6 +1381,66 @@ func main() {
    }
    ```

    Here is a similar version that sorts by name and age:

    ```go
    package main

    import (
    "fmt"
    "sort"
    )

    type person struct {
    Name string
    Age int
    }

    type byName []person

    func (p byName) Len() int {
    return len(p)
    }
    func (p byName) Less(i, j int) bool {
    return p[i].Name < p[j].Name
    }
    func (p byName) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
    }

    type byAge []person

    func (p byAge) Len() int {
    return len(p)
    }
    func (p byAge) Less(i, j int) bool {
    return p[i].Age < p[j].Age
    }
    func (p byAge) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
    }

    func main() {
    kids := []person{
    {"Jill", 9},
    {"Jack", 10},
    }

    sort.Sort(byName(kids))
    fmt.Println(kids)

    sort.Sort(byAge(kids))
    fmt.Println(kids)
    }
    ```

    Which results in:

    ```
    [{Jack 10} {Jill 9}]
    [{Jill 9} {Jack 10}]
    ```

    ### Read Users Input

    ```go
  11. @Integralist Integralist revised this gist Dec 30, 2015. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -3061,6 +3061,7 @@ import "fmt"
    const (
    foo = iota // 0
    bar
    _ // skip this value
    baz
    )

    @@ -3070,7 +3071,7 @@ const (
    )

    func main() {
    fmt.Println(foo, bar, baz) // 0 1 2
    fmt.Println(foo, bar, baz) // 0 1 3
    fmt.Println(beep, boop) // 0 1
    }
    ```
  12. @Integralist Integralist revised this gist Dec 30, 2015. 1 changed file with 27 additions and 0 deletions.
    27 changes: 27 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -52,6 +52,7 @@
    - [Zip File Contents](#zip-file-contents)
    - [OAuth](https://gist.github.com/Integralist/0e277a517fee68153f93)
    - [RPC](#rpc)
    - [Enumerator IOTA](#enumerator-iota)

    ## Shell exports

    @@ -3046,4 +3047,30 @@ func main() {

    fmt.Printf("The reply pointer value has been changed to: %d", reply)
    }
    ```

    ### Enumerator IOTA

    Within a constant declaration, the predeclared identifier `iota` represents successive untyped integer constants. It is reset to 0 whenever the reserved word `const` appears in the source.

    ```go
    package main

    import "fmt"

    const (
    foo = iota // 0
    bar
    baz
    )

    const (
    beep = iota // 0 (reset)
    boop
    )

    func main() {
    fmt.Println(foo, bar, baz) // 0 1 2
    fmt.Println(beep, boop) // 0 1
    }
    ```
  13. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 35 additions and 0 deletions.
    35 changes: 35 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2829,6 +2829,41 @@ foo: {X:8 Y:8}
    {Circle:{Point:{X:8 Y:8} Radius:5} Spokes:20}
    ```

    Here is a more practical example that demonstrates how embedded functionality can make code more expressive:

    ```go
    package main

    import (
    "fmt"
    "sync"
    )

    // Anonymous struct
    var cache = struct {
    sync.Mutex
    mapping map[string]string
    }{
    mapping: make(map[string]string), // initial zero value for map
    }

    func setValue() {
    cache.Lock()
    cache.mapping["foo"] = "bar"
    cache.Unlock()
    }

    func main() {
    setValue()

    cache.Lock()
    v := cache.mapping["foo"]
    cache.Unlock()

    fmt.Printf("v: %s", v)
    }
    ```

    ### Zip File Contents

    ```go
  14. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2792,7 +2792,6 @@ package main

    import "fmt"

    // Point does stuff
    type Point struct {
    X, Y int
    }
  15. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 45 additions and 0 deletions.
    45 changes: 45 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2785,6 +2785,51 @@ Which prints:

    > Note: anonymous fields don't work shorthand literal Struct
    The following example demonstrates how methods of a composited object can be accessed from the consuming object:

    ```go
    package main

    import "fmt"

    // Point does stuff
    type Point struct {
    X, Y int
    }

    func (p Point) foo() {
    fmt.Printf("foo: %+v\n", p)
    }

    type Circle struct {
    Point
    Radius int
    }

    type Wheel struct {
    Circle
    Spokes int
    }

    func main() {
    var w Wheel
    w.X = 8 // w.Circle.Point.X
    w.Y = 8 // w.Circle.Point.Y
    w.foo() // w.Circle.Point.foo()
    w.Radius = 5 // w.Circle.Radius
    w.Spokes = 20

    fmt.Printf("%+v", w)
    }
    ```

    Which prints:

    ```
    foo: {X:8 Y:8}
    {Circle:{Point:{X:8 Y:8} Radius:5} Spokes:20}
    ```

    ### Zip File Contents

    ```go
  16. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -1882,7 +1882,7 @@ func main() {
    }
    ```

    > Note: compiler can only apply implicit dereference for variables and struct fields
    > Note: compiler can only apply implicit dereference for variables and struct fields
    > this wouldn't work `Point{1, 2}.scaleBy(5)`
    Results in the following output:
  17. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -1882,6 +1882,9 @@ func main() {
    }
    ```

    > Note: compiler can only apply implicit dereference for variables and struct fields
    > this wouldn't work `Point{1, 2}.scaleBy(5)`
    Results in the following output:

    ```
  18. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -1849,12 +1849,14 @@ type Point struct {
    y int
    }

    // If receiver Point isn't a pointer then struct value isn't updated
    // If receiver (Point) isn't set to a pointer (*Point)
    // then the struct's field value won't be updated outside the method
    func (p *Point) scaleBy(factor int) {
    fmt.Printf("scaleBy (before modification): %+v\n", p)

    // Don't need to derefence (*) struct fields
    // That's only needed when passing pointer variables into a standard function
    // Compiler will perform an implicit &p for you
    // You only need to dereference in standard functions when a argument pointer is required (see below Array Pointer example)
    p.x *= factor
    p.y *= factor

  19. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 60 additions and 0 deletions.
    60 changes: 60 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -34,6 +34,7 @@
    - [TLS HTTP Request](#tls-http-request)
    - [Custom HTTP Request](#custom-http-request)
    - [HTTP GET Web Page](#http-get-web-page)
    - [Pointers](#pointers)
    - [Array Pointer](#array-pointer)
    - [Type Assertion](#type-assertion)
    - [Line Count](#line-count)
    @@ -1835,6 +1836,65 @@ func main() {
    }
    ```

    ### Pointers

    ```go
    package main

    import "fmt"

    // Point stores co-ordinates
    type Point struct {
    x int
    y int
    }

    // If receiver Point isn't a pointer then struct value isn't updated
    func (p *Point) scaleBy(factor int) {
    fmt.Printf("scaleBy (before modification): %+v\n", p)

    // Don't need to derefence (*) struct fields
    // That's only needed when passing pointer variables into a standard function
    p.x *= factor
    p.y *= factor

    fmt.Printf("scaleBy (after modification): %+v\n", p)
    }

    func main() {
    // Doesn't matter if we do or don't get the address space (&) for foo/bar's Point
    foo := &Point{1, 2}
    bar := &Point{6, 8}

    fmt.Printf("Main foo.x: %+v\n", foo.x)
    fmt.Printf("Main bar.x: %+v\n", bar.x)

    foo.scaleBy(5)
    bar.scaleBy(5)

    fmt.Printf("Main foo.x: %+v\n", foo.x)
    fmt.Printf("Main foo.y: %+v\n", foo.y)

    fmt.Printf("Main bar.x: %+v\n", bar.x)
    fmt.Printf("Main bar.y: %+v\n", bar.y)
    }
    ```

    Results in the following output:

    ```
    Main foo.x: 1
    Main bar.x: 6
    scaleBy (before modification): &{x:1 y:2}
    scaleBy (after modification): &{x:5 y:10}
    scaleBy (before modification): &{x:6 y:8}
    scaleBy (after modification): &{x:30 y:40}
    Main foo.x: 5
    Main foo.y: 10
    Main bar.x: 30
    Main bar.y: 40
    ```

    ### Array Pointer

    Deference an Array pointer so you can mutate the original Array values:
  20. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2795,6 +2795,8 @@ func main() {

    ### RPC

    For details of what RPC means, see: https://gist.github.com/Integralist/f5856b94e002bcfd4ce7

    Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored:

    - the method's type is exported.
  21. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 110 additions and 0 deletions.
    110 changes: 110 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -50,6 +50,7 @@
    - [Embedded Structs](#embedded-structs)
    - [Zip File Contents](#zip-file-contents)
    - [OAuth](https://gist.github.com/Integralist/0e277a517fee68153f93)
    - [RPC](#rpc)

    ## Shell exports

    @@ -2790,4 +2791,113 @@ func main() {
    return
    }
    }
    ```

    ### RPC

    Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored:

    - the method's type is exported.
    - the method is exported.
    - the method has two arguments, both exported (or builtin) types.
    - the method's second argument is a pointer.
    - the method has return type error.

    In effect, the method must look schematically like

    ```go
    func (t *T) MethodName(argType T1, replyType *T2) error
    ```

    The setup for a simple RPC example is:

    1. Create remote package Foo that will consist of functions to be made available via RPC
    2. Create remote package that will expose package Foo
    3. Create client package that connects to remote via RPC

    So here is the package that consists of functions to be made available via RPC:

    ```go
    package remote

    import "fmt"

    // Args is a data structure for the incoming arguments
    type Args struct {
    A, B int
    }

    // Arith is our functions return type
    type Arith int

    // Multiply does simply multiplication on provided arguments
    func (t *Arith) Multiply(args *Args, reply *int) error {
    fmt.Printf("Args received: %+v\n", args)
    *reply = args.A * args.B
    return nil
    }
    ```

    Here is the remote package that exposes the other package of functionality:

    ```go
    package main

    import (
    "log"
    "net"
    "net/rpc"

    "github.com/integralist/rpc/remote"
    )

    func main() {
    arith := new(remote.Arith)

    rpc.Register(arith)
    rpc.HandleHTTP()

    l, e := net.Listen("tcp", ":1234")
    if e != nil {
    log.Fatal("listen error:", e)
    }

    rpc.Accept(l)
    }
    ```

    Here is our client code for connecting to our remote package via RPC:

    ```go
    package main

    import (
    "fmt"
    "log"
    "net"
    "net/rpc"
    "time"
    )

    type args struct {
    A, B int
    }

    func main() {
    conn, err := net.DialTimeout("tcp", "localhost:1234", time.Minute)
    if err != nil {
    log.Fatal("dialing:", err)
    }

    client := rpc.NewClient(conn)

    var reply int

    e := client.Call("Arith.Multiply", &args{4, 2}, &reply)
    if e != nil {
    log.Fatalf("Something went wrong: %s", err.Error())
    }

    fmt.Printf("The reply pointer value has been changed to: %d", reply)
    }
    ```
  22. @Integralist Integralist revised this gist Dec 29, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -49,6 +49,7 @@
    - [Comparing maps](#comparing-maps)
    - [Embedded Structs](#embedded-structs)
    - [Zip File Contents](#zip-file-contents)
    - [OAuth](https://gist.github.com/Integralist/0e277a517fee68153f93)

    ## Shell exports

  23. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2760,7 +2760,7 @@ func main() {

    zdest := zlib.NewWriter(dest)
    if _, err := io.Copy(zdest, openSrc); err != nil {
    log.Fatal(err)
    return
    }

    // Close these explicitly
  24. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 75 additions and 1 deletion.
    76 changes: 75 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -48,6 +48,7 @@
    - [Socket programming with TCP server](#socket-programming-with-tcp-server)
    - [Comparing maps](#comparing-maps)
    - [Embedded Structs](#embedded-structs)
    - [Zip File Contents](#zip-file-contents)

    ## Shell exports

    @@ -2715,4 +2716,77 @@ Which prints:
    {Circle:{Point:{X:8 Y:8} Radius:5} Spokes:20}
    ```

    > Note: anonymous fields don't work shorthand literal Struct
    > Note: anonymous fields don't work shorthand literal Struct
    ### Zip File Contents

    ```go
    package main

    import (
    "compress/zlib"
    "io"
    "log"
    "os"
    )

    func main() {
    var err error

    // This defends against an error preventing `defer` from being called
    // As log.Fatal otherwise calls `os.Exit`
    defer func() {
    if err != nil {
    log.Fatalln("\nDeferred log: \n", err)
    }
    }()

    src, err := os.Create("source.txt")
    if err != nil {
    return
    }
    src.WriteString("source content")
    src.Close()

    dest, err := os.Create("new.txt")
    if err != nil {
    return
    }

    openSrc, err := os.Open("source.txt")
    if err != nil {
    return
    }

    zdest := zlib.NewWriter(dest)
    if _, err := io.Copy(zdest, openSrc); err != nil {
    log.Fatal(err)
    }

    // Close these explicitly
    zdest.Close()
    dest.Close()

    n, err := os.Open("new.txt")
    if err != nil {
    return
    }

    r, err := zlib.NewReader(n)
    if err != nil {
    return
    }
    defer r.Close()
    io.Copy(os.Stdout, r)

    err = os.Remove("source.txt")
    if err != nil {
    return
    }

    err = os.Remove("new.txt")
    if err != nil {
    return
    }
    }
    ```
  25. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2494,7 +2494,7 @@ There are two main types of sockets:
    The principle steps behind a socket is:

    - Create the socket
    - Bind the socket to an address (e.g. 127.0.0.1:80)
    - Bind the socket to an address (e.g. `127.0.0.1:80`)
    - Listen for socket connections
    - Accept the socket connection

  26. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 16 additions and 1 deletion.
    17 changes: 16 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -2483,7 +2483,22 @@ func main() {

    ### Socket programming with TCP server

    There are two main packages: `server.go` and `client.go`.
    There are two main types of sockets:

    1. STREAM sockets (e.g. TCP)
    2. DATAGRAM sockets (e.g. UDP)

    > Note: a "unix domain socket" is actually a physical file
    > it's useful for local (same host) data communication
    The principle steps behind a socket is:

    - Create the socket
    - Bind the socket to an address (e.g. 127.0.0.1:80)
    - Listen for socket connections
    - Accept the socket connection

    There are two main packages in our below example: `server.go` and `client.go`.

    Run both of them in separate terminals (e.g. `go run ...`)

  27. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 41 additions and 0 deletions.
    41 changes: 41 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -11,6 +11,7 @@
    - [Dependencies with glide](#dependencies-with-glide)
    - [Documentation](#documentation)
    - [Testing](#testing)
    - [Logging](#logging)
    - [Bits, Bytes, Runes](#bits-bytes-runes)
    - [Code Examples](#code-examples)
    - [New vs Make](#new-vs-make)
    @@ -849,6 +850,46 @@ func err(response, expected string, t *testing.T) {
    }
    ```

    ## Logging

    ```go
    package main

    import (
    "os"

    log "github.com/Sirupsen/logrus"
    )

    func main() {
    // Standard stdout ASCII logging
    log.WithFields(log.Fields{
    "animal": "walrus",
    }).Info("A walrus appears")

    // JSON style structured logging
    log.SetFormatter(&log.JSONFormatter{})
    f, e := os.Create("logs")
    if e != nil {
    log.Fatal("Failed to create log file")
    }
    log.SetOutput(f)
    log.WithFields(log.Fields{
    "animal": "walrus",
    "size": 10,
    }).Info("A group of walrus emerges from the ocean")
    /*
    {
    "animal": "walrus",
    "level": "info",
    "msg": "A group of walrus emerges from the ocean",
    "size": 10,
    "time": "2015-12-22T13:58:46Z"
    }
    */
    }
    ```

    ## Bits, Bytes, Runes

    https://pythonconquerstheuniverse.wordpress.com/2010/05/30/unicode-beginners-introduction-for-dummies-made-simple/
  28. @Integralist Integralist revised this gist Dec 22, 2015. 1 changed file with 77 additions and 0 deletions.
    77 changes: 77 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -41,6 +41,7 @@
    - [Time and Channels](#time-and-channels)
    - [Quit a Channel](#quit-a-channel)
    - [Starting and Stopping things with Channels](#starting-and-stopping-things-with-channels)
    - [Channel Pipelines](#channel-pipelines)
    - [Templating](#templating)
    - [Error handling with context](#error-handling-with-context)
    - [Socket programming with TCP server](#socket-programming-with-tcp-server)
    @@ -2221,6 +2222,82 @@ func main() {
    }
    ```

    ### Channel Pipelines

    The principle of a pipeline, is to take data from one function and pass it into another function, that receiving function will process the received data and then that result is returned and subsequently passed onto another function... rinse and repeat for however long your pipeline needs to be.

    In the below example (copied from [here](https://blog.gopheracademy.com/advent-2015/automi-stream-processing-over-go-channels/)) demonstrates how a set of functions accept a channel and return a channel and so channels is the 'data' that is passed around the pipeline functions:

    ```go
    package main

    import "fmt"
    import "sync"

    func ingest() <-chan []string {
    out := make(chan []string)
    go func() {
    out <- []string{"aaaa", "bbb"}
    out <- []string{"cccccc", "dddddd"}
    out <- []string{"e", "fffff", "g"}
    close(out)
    }()
    return out
    }

    func process(concurrency int, in <-chan []string) <-chan int {
    var wg sync.WaitGroup
    wg.Add(concurrency)

    out := make(chan int)

    work := func() {
    for data := range in {
    for _, word := range data {
    out <- len(word)
    }
    }
    wg.Done()

    }

    go func() {
    for i := 0; i < concurrency; i++ {
    go work()
    }

    }()

    go func() {
    wg.Wait()
    close(out)
    }()
    return out
    }

    func store(in <-chan int) <-chan struct{} {
    done := make(chan struct{})
    go func() {
    defer close(done)
    for data := range in {
    fmt.Println(data)
    }
    }()
    return done
    }

    func main() {
    // stage 1 ingest data from source
    in := ingest()

    // stage 2 - process data
    reduced := process(4, in)

    // stage 3 - store
    <-store(reduced)
    }
    ```

    ### Templating

    Here is a basic program that uses a Struct for its data source:
  29. @Integralist Integralist revised this gist Dec 19, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -545,7 +545,7 @@ go get github.com/Masterminds/glide
    export GO15VENDOREXPERIMENT=1 # or use 1.6
    glide init # generates glide.yaml
    glide install # installs from lock file (creates it if not found)
    glide update # downloads dependencies and update lock file
    glide update # updates dependencies and updates lock file
    glide list # shows vendored deps
    go test $(glide novendor) # test only your package (not vendored packages)
    ```
  30. @Integralist Integralist revised this gist Dec 19, 2015. 1 changed file with 19 additions and 0 deletions.
    19 changes: 19 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,7 @@
    - [Build and Compilation](#build-and-compilation)
    - [Dependencies with godeps](#dependencies-with-godeps)
    - [Dependencies with gb](#dependencies-with-gb)
    - [Dependencies with glide](#dependencies-with-glide)
    - [Documentation](#documentation)
    - [Testing](#testing)
    - [Bits, Bytes, Runes](#bits-bytes-runes)
    @@ -533,6 +534,24 @@ You'll need the following structure:

    The `vendor` directory is auto-generated by the `gb vendor fetch <pkg>` command.

    ## Dependencies with glide

    This is now my preferred dependency management tool, as it works just like existing tools in other languages (e.g. Ruby's Bundler or Node's NPM) and so consistency is a plus.

    It also provides the ability (like gb) to not commit dependencies but have specific versions vendored when running a simple command.

    ```bash
    go get github.com/Masterminds/glide
    export GO15VENDOREXPERIMENT=1 # or use 1.6
    glide init # generates glide.yaml
    glide install # installs from lock file (creates it if not found)
    glide update # downloads dependencies and update lock file
    glide list # shows vendored deps
    go test $(glide novendor) # test only your package (not vendored packages)
    ```

    > Note: to add a new dependency `glide get <pkg_name>`
    ## Documentation

    `Godoc` is the original implementation for viewing documentation. Previous to `Godoc` there was `go doc`, but that was removed and then added *back* with totally different functionality.