Skip to content

Instantly share code, notes, and snippets.

@jemakom
Forked from Integralist/Golang Essentials.md
Created April 20, 2016 11:24
Show Gist options
  • Select an option

  • Save jemakom/0aca8125b3bf9c923ab412a020e6c572 to your computer and use it in GitHub Desktop.

Select an option

Save jemakom/0aca8125b3bf9c923ab412a020e6c572 to your computer and use it in GitHub Desktop.

Revisions

  1. @Integralist Integralist revised this gist Mar 21, 2016. 1 changed file with 43 additions and 0 deletions.
    43 changes: 43 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -25,6 +25,7 @@
    - [See all methods of a <Type>](#see-all-methods-of-a-type)
    - [Set time](#set-time)
    - [Convert Struct into JSON](#convert-struct-into-json)
    - [Extract only JSON you need](#extract-only-json-you-need)
    - [Nested JSON handling](#nested-json-handling)
    - [Pretty Printing JSON String](#pretty-printing-json-string)
    - [Nested YAML handling](#nested-yaml-handling)
    @@ -1520,6 +1521,48 @@ func main() {
    }
    ```

    ### Extract only JSON you need

    https://medium.com/the-hoard/using-golang-and-json-for-kafka-consumption-with-high-throughput-4cae28e08f90#.7rcmae71b

    Effectively the solution is:

    ```go
    /*
    imagine our variable 'bytes' contains some JSON with lots of fields
    we only want the fields 'type' and 'id'
    we should get our provider of data to transform everything else inside a 'data' field
    e.g.
    {
    “id”: “numero uno”,
    “type”: “transaction”,
    // data is the JSON msg from above
    “data”: {
    “id”: “numero uno”,
    “type”: “transaction”,
    // … a whole bunch of dynamic fields
    “amount”: “1000”,
    “currency”: “usd”,
    // … etc.
    }
    }
    */

    type Message struct {
    ID string `json:”id”`
    Type string `json:”type”`
    Data json.RawMessage `json:”data”`
    }

    var m Message
    json.Unmarshal(bytes, &m)
    es.Index(index, m.Type, m.ID, "", "", nil, m.Data, false)
    ```

    This way we only decode the id and type, so we're being performant, and then we pass the original raw JSON onto our next service (e.g. `es` ElasticSearch) to do with what they please.

    ### Nested JSON handling

    ```go
  2. @Integralist Integralist revised this gist Feb 18, 2016. 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
    @@ -3691,6 +3691,9 @@ func main() {

    There is another option (which is required if using another programming language to communicate with your Go RPC service), that is to turn your RPC into a JSON RPC.

    > This is because the standard net/rpc uses https://golang.org/pkg/encoding/gob/
    > Which is a Go specific streaming binary format
    Effectively just use the same example as above but make the following changes:

    - `net/rpc` to `net/rpc/jsonrpc`
  3. @Integralist Integralist revised this gist Feb 18, 2016. 1 changed file with 29 additions and 14 deletions.
    43 changes: 29 additions & 14 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -3702,34 +3702,49 @@ Now your clients can connect via a TCP socket and pass over JSON, as shown in Ru
    ```ruby
    require "socket"
    require "json"
    require "pry"

    socket = TCPSocket.new "localhost", "8080"

    # Details of JSON structure can be found here:
    # https://golang.org/src/net/rpc/jsonrpc/client.go#L45
    # Thanks to Albert Hafvenström (@albhaf) for his help
    b = {
    method: "Compose.Details",
    params: "foobar"
    :method => "Compose.Details",
    :params => [{ :Foo => "Foo!", :Bar => "Bar!" }],
    :id => "0" # id is just echo'ed back to the client
    }

    binding.pry

    socket.write(JSON.dump(b))

    resp = JSON.load(socket.readline)
    p JSON.load(socket.readline)

    p resp
    # => {"id"=>"0", "result"=>"Blah!", "error"=>nil}
    ```

    Or even shorter if using a library:
    Here is an updated Go RPC:

    ```ruby
    require "jimson"
    require "pry"
    ```go
    package remote

    binding.pry
    import "fmt"

    client = Jimson::Client.new("localhost:8080")
    result = client.Compose.Details("foobar")
    // Args is structured around the client's provided parameters
    // The fields need to be exported too!
    type Args struct {
    Foo string
    Bar string
    }

    // Compose is our RPC functions return type
    type Compose string

    // Details is our exposed RPC function
    func (c *Compose) Details(args *Args, reply *string) error {
    fmt.Printf("Args received: %+v\n", args)
    *c = "some value"
    *reply = "Blah!"
    return nil
    }
    ```

    ### Enumerator IOTA
  4. @Integralist Integralist revised this gist Feb 17, 2016. 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
    @@ -3687,6 +3687,51 @@ func main() {
    }
    ```

    #### JSON RPC

    There is another option (which is required if using another programming language to communicate with your Go RPC service), that is to turn your RPC into a JSON RPC.

    Effectively just use the same example as above but make the following changes:

    - `net/rpc` to `net/rpc/jsonrpc`
    - `rpc.Dial` to `jsonrpc.Dial`
    - `rpc.ServeConn` to `jsonrpc.ServeConn`

    Now your clients can connect via a TCP socket and pass over JSON, as shown in Ruby below:

    ```ruby
    require "socket"
    require "json"
    require "pry"

    socket = TCPSocket.new "localhost", "8080"

    b = {
    method: "Compose.Details",
    params: "foobar"
    }

    binding.pry

    socket.write(JSON.dump(b))

    resp = JSON.load(socket.readline)

    p resp
    ```

    Or even shorter if using a library:

    ```ruby
    require "jimson"
    require "pry"

    binding.pry

    client = Jimson::Client.new("localhost:8080")
    result = client.Compose.Details("foobar")
    ```

    ### 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.
  5. @Integralist Integralist revised this gist Feb 15, 2016. 1 changed file with 100 additions and 1 deletion.
    101 changes: 100 additions & 1 deletion Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -3499,6 +3499,13 @@ The setup for a simple RPC example is:
    2. Create remote package that will expose package Foo
    3. Create client package that connects to remote via RPC

    There are two variations:

    1. RPC over HTTP
    2. RPC over TCP

    #### HTTP

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

    ```go
    @@ -3586,7 +3593,99 @@ func main() {
    }
    ```

    http://stackoverflow.com/questions/19640005/golang-rpc-http-serve-vs-rpc-serveconn-http-vs-raw-connection
    #### TCP

    Remote RPC Function:

    ```go
    package remote

    import "fmt"

    // Compose is our RPC functions return type
    type Compose string

    // Details is our exposed RPC function
    func (c *Compose) Details(arg string, reply *string) error {
    fmt.Printf("Arg received: %+v\n", arg)
    *c = "some value"
    *reply = "Blah!"
    return nil
    }
    ```

    Remote RPC Endpoint Exposed:

    ```go
    package remote

    import (
    "fmt"
    "net"
    "net/rpc"

    "github.com/bbc/mozart-api-common/logger"
    )

    // Endpoint exposes our RPC over TCP service
    func Endpoint() {
    compose := new(Compose)

    rpc.Register(compose)
    // rpc.HandleHTTP()

    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
    logMessage := map[string]interface{}{
    "event": "FailedTCPListenerConnection",
    "message": fmt.Sprintf("Listener failed to open TCP port 8080: %v", err),
    }
    logger.Error(logMessage)
    }

    // rpc.Accept(listener)
    for {
    conn, err := listener.Accept()
    if err != nil {
    logMessage := map[string]interface{}{
    "event": "FailedTPCIncomingConnection",
    "message": fmt.Sprintf("Listener failed to accept an incoming connection: %v", err),
    }
    logger.Error(logMessage)
    }

    go rpc.ServeConn(conn)
    }
    }
    ```

    Client Connection over TCP to Remote RPC function:

    ```go
    package main

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

    func main() {
    client, err := rpc.Dial("tcp", "localhost:8080")
    if err != nil {
    log.Fatal("dialing:", err)
    }

    var reply string

    e := client.Call("Compose.Details", "my string", &reply)
    if e != nil {
    log.Fatalf("Something went wrong: %v", e.Error())
    }

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

    ### Enumerator IOTA

  6. @Integralist Integralist revised this gist Feb 15, 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
    @@ -3696,8 +3696,8 @@ func (c *Compose) Details() string {
    func main() {
    var c Compose
    c = "hai"
    fmt.Printf("c: %+v\n", c)
    fmt.Printf("c: %+v\n", c) // c
    fmt.Println(c.Details())
    fmt.Printf("c: %+v\n", c)
    fmt.Printf("c: %+v\n", c) // beep boop
    }
    ```
  7. @Integralist Integralist revised this gist Feb 15, 2016. 1 changed file with 24 additions and 0 deletions.
    24 changes: 24 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -62,6 +62,7 @@
    - [FizzBuzz](#fizzbuzz)
    - [Execute Shell Command](#execute-shell-command)
    - [New Instance Idiom](#new-instance-idiom)
    - [Mutating Values](#mutating-values)

    ## Install

    @@ -3676,4 +3677,27 @@ func main() {
    fmt.Println(s.foo)
    s.create()
    }
    ```

    ### Mutating Values

    ```go
    package main

    import "fmt"

    type Compose string

    func (c *Compose) Details() string {
    *c = "beep boop"
    return fmt.Sprintf("Here are your details: %v", *c)
    }

    func main() {
    var c Compose
    c = "hai"
    fmt.Printf("c: %+v\n", c)
    fmt.Println(c.Details())
    fmt.Printf("c: %+v\n", c)
    }
    ```
  8. @Integralist Integralist revised this gist Feb 15, 2016. 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
    @@ -3585,6 +3585,8 @@ func main() {
    }
    ```

    http://stackoverflow.com/questions/19640005/golang-rpc-http-serve-vs-rpc-serveconn-http-vs-raw-connection

    ### 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.
  9. @Integralist Integralist revised this gist Feb 13, 2016. 1 changed file with 28 additions and 0 deletions.
    28 changes: 28 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -24,6 +24,7 @@
    - [Reference vs Value](#reference-vs-value)
    - [See all methods of a <Type>](#see-all-methods-of-a-type)
    - [Set time](#set-time)
    - [Convert Struct into JSON](#convert-struct-into-json)
    - [Nested JSON handling](#nested-json-handling)
    - [Pretty Printing JSON String](#pretty-printing-json-string)
    - [Nested YAML handling](#nested-yaml-handling)
    @@ -1491,6 +1492,33 @@ expiration := now.Add(time.Hour * 24 * 30)
    fmt.Println("Thirty days from now will be : ", expiration)
    ```

    ### Convert Struct into JSON

    ```go
    package main

    import (
    "encoding/json"
    "fmt"
    "os"
    "time"
    )

    func main() {
    type Message struct {
    Sequence int `json:"sequence"`
    Title string `json:"title"`
    Timestamp time.Time `json:"timestamp"`
    }
    msg := Message{1, "Foobar", time.Now()}
    b, err := json.Marshal(msg)
    if err != nil {
    fmt.Println("error:", err)
    }
    os.Stdout.Write(b)
    }
    ```

    ### Nested JSON handling

    ```go
  10. @Integralist Integralist revised this gist Feb 13, 2016. 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
    @@ -60,6 +60,7 @@
    - [Enumerator IOTA](#enumerator-iota)
    - [FizzBuzz](#fizzbuzz)
    - [Execute Shell Command](#execute-shell-command)
    - [New Instance Idiom](#new-instance-idiom)

    ## Install

    @@ -3619,4 +3620,30 @@ if cmdOut, err = exec.Command(cmdName, cmdArgs...).Output(); err != nil {
    os.Exit(1)
    }
    fmt.Println(string(cmdOut))
    ```

    ### New Instance Idiom

    ```go
    package main

    import "fmt"

    type Sqs struct {
    foo string
    }

    func (s *Sqs) create() {
    fmt.Println("I'll create stuff")
    }

    func NewSqs() *Sqs {
    return &Sqs{"bop"}
    }

    func main() {
    s := NewSqs()
    fmt.Println(s.foo)
    s.create()
    }
    ```
  11. @Integralist Integralist revised this gist Feb 13, 2016. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -246,6 +246,14 @@ func main() {

    ### Create SQS queue

    Usage:

    ```
    go run local/create.go -queue "producer"
    ```

    Code:

    ```go
    package main

  12. @Integralist Integralist revised this gist Feb 13, 2016. 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
    @@ -6,7 +6,7 @@
    - [Guard (automatic go run)](#guard-automatic-go-run)
    - [Godo](#godo)
    - [Spurious](#spurious)
    - [AWS SDK with Go (OLD!)](#aws-sdk-with-go)
    - [AWS SDK with Go (inc. some old possibly broken examples)](#aws-sdk-with-go)
    - [Build and Compilation](#build-and-compilation)
    - [Dependency information with `go list`](#dependency-information-with-go-list)
    - [Dependencies with godeps](#dependencies-with-godeps)
  13. @Integralist Integralist revised this gist Feb 13, 2016. 1 changed file with 100 additions and 0 deletions.
    100 changes: 100 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -244,6 +244,106 @@ func main() {
    }
    ```

    ### Create SQS queue

    ```go
    package main

    import (
    "encoding/json"
    "flag"
    "fmt"
    "log"
    "os"
    "os/exec"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/awserr"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sqs"
    )

    type network []struct {
    Host string
    HostPort string
    }

    type spurious struct {
    Sqs network `json:"spurious-sqs"`
    S3 network `json:"spurious-s3"`
    Dynamo network `json:"spurious-dynamo"`
    }

    var (
    svc *sqs.SQS
    queueName string
    regionName string
    endpointName string
    cmdOut []byte
    err error
    spur spurious
    )

    var region = flag.String("region", "eu-west-1", "Name of region to create the resource within")
    var queue = flag.String("queue", "producer", "Name of queue to be created")
    var endpoint = flag.String("endpoint", "", "Spurious endpoint")

    func init() {
    flag.Parse()

    queueName = *queue
    regionName = *region
    endpointName = *endpoint

    if endpointName == "" {
    cmdName := "spurious"
    cmdArgs := []string{"ports", "--json"}
    if cmdOut, err = exec.Command(cmdName, cmdArgs...).Output(); err != nil {
    fmt.Fprintln(os.Stderr, "There was an error running 'spurious ports --json' command: ", err)
    os.Exit(1)
    }

    json.Unmarshal(cmdOut, &spur)
    endpointName = spur.Sqs[0].Host + ":" + spur.Sqs[0].HostPort
    }

    svc = sqs.New(
    session.New(),
    &aws.Config{
    Region: aws.String(regionName),
    DisableSSL: aws.Bool(true),
    Endpoint: aws.String(endpointName),
    })
    }

    func main() {
    params := &sqs.CreateQueueInput{
    QueueName: aws.String(queueName),
    }

    resp, err := svc.CreateQueue(params)

    if err != nil {
    if awsErr, ok := err.(awserr.Error); ok {
    // Get error details
    log.Println("Error:", awsErr.Code(), awsErr.Message())

    // Prints out full error message, including original error if there was one.
    log.Println("Error:", awsErr.Error())

    // Get original error
    if origErr := awsErr.OrigErr(); origErr != nil {
    // operate on original error.
    }
    } else {
    fmt.Println(err.Error())
    }
    }

    fmt.Println(resp)
    }
    ```

    ### Possibly Broken Examples

    **UPDATE** the following code examples are now old and probably don't work any more
  14. @Integralist Integralist revised this gist Feb 13, 2016. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions Golang Essentials.md
    Original file line number Diff line number Diff line change
    @@ -59,6 +59,7 @@
    - [RPC](#rpc)
    - [Enumerator IOTA](#enumerator-iota)
    - [FizzBuzz](#fizzbuzz)
    - [Execute Shell Command](#execute-shell-command)

    ## Install

    @@ -3494,4 +3495,20 @@ func main() {
    }
    }
    }
    ```

    ### Execute Shell Command

    ```go
    var (
    cmdOut []byte
    err error
    )
    cmdName := "spurious"
    cmdArgs := []string{"ports", "--json"}
    if cmdOut, err = exec.Command(cmdName, cmdArgs...).Output(); err != nil {
    fmt.Fprintln(os.Stderr, "There was an error running 'spurious ports --json' command: ", err)
    os.Exit(1)
    }
    fmt.Println(string(cmdOut))
    ```
  15. @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:

  16. @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).
  17. @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`
  18. @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)
    }
    }
    }
    ```
  19. @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:
  20. @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

  21. @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
  22. @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)
  23. @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
  24. @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
  25. @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
    }
    ```
  26. @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
    }
    ```
  27. @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
  28. @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
    }
  29. @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
  30. @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: