Today I Learned

A Hashrocket project

9 posts about #go

Upgrading From An Older Version On Mac

To upgrade from an older version on Mac, there are a couple manual steps that you need to take. For starters, download the latest installer for Mac from Go Lang Downloads.

While this is downloading, you’ll need to delete the older version of Go that is installed on your machine.

First, remove the existing Go installation directory:

$ sudo rm -rf /usr/local/go

Second, clean up the Go bin directory from your PATH environment variable:

$ sudo rm /etc/paths.d/go

Now, you can double click on the downloaded installer dmg and follow the prompt instructions.

When its all said and done, check go version from the command line to see that you are now working with the latest.

Private vs Public Struct members

In Golang, identifiers can be either Exported or Unexported. In other languages this would be known as public or private, but in golang the question is whether the identifiers should be able to be seen outside of the module. If not? Don’t export them.

The rule is simple, if an identifier is capitalized it will be exported. This manifests itself in golang when converting a struct to JSON.

type Apple struct {
    color string
    weight int
}

a := json.Marshal(Apple{"green", 10})
fmt.Println(a)

In this case this code will print {}. To print what you would expect the struct should be defined with capitalized identifiers:

type Apple struct {
    Color string
    Weight int
}

Now the marshalled struct should be {"Color": "green", "Weight": 10}

Installing the Golang tools with Vim

Go has a set of tools to help aid in go development such as a test coverage tool for go or go guru (a tool for answering questions about the go source code.

While in vim if you would like to install these tools just use the command:

:GoInstallBinaries

And likewise if you would like to update these tools use the command

:GoUpdateBinaries

These commands are provided by the vim-go vim plugin. The binaries are installed into your $GOPATH directory or if you’d like to override that dir set the g:go_bin_path vim variable.

Quick Garbage Collector Stats from Go Programs

Set the GODEBUG=gctrace=1 in the environment to get log output from a Go program whenever the garbage collector runs.

Example:

gc 1 @10.282s 0%: 0.12+0.17+0.10 ms clock, 0.38+0/0.053/0.19+0.30 ms cpu, 4->4->0 MB, 5 MB goal, 4 P

The clock and cpu sections give us details on how long the GC cycle took. In this case we can see that it took well under 1ms.

See https://golang.org/pkg/runtime/ for details on what the output means.

Sleep For A Duration

Many languages allow you to sleep for a certain number of milliseconds. In those languages, you can give 500 or 1000 to the sleep function to sleep for half a second and a second respectively. In Go, the duration of a call to time.Sleep is in nanoseconds. Fortunately, there are constants that make it easy to sleep in terms of milliseconds.

For example, you can sleep for a half a second (500 milliseconds) like so:

package main

import (
    "time"
)

func main() {
    time.Sleep(500 * time.Millisecond)
}

Other available time constants are Nanosecond, Microsecond, Second, Minute, Hour.

Seeding Golang's rand

‘Random’ numbers in Go don’t always seem random. This is because the rand package defaults to a seed of 1.

That’s great if you need a bunch of random numbers at the start of your program. Not great if you expect a different outcome each time you run the program.

A solution is to seed rand with Unix time. Try it in the init() function:

package main

import (
    "math/rand"
    "time"
)

func init() {
    rand.Seed(time.Now().UTC().UnixNano())
}
...

Replace The Current Process With An External Cmd

Go’s syscall.Exec function can be used to execute an external program. Instead of forking a child process though, it runs the external command in place of the current process. You need to give the function three pieces of information: the location of the binary, the pieces of the command to be executed, and relevant environment variables. Here is a simple example.

package main

import "fmt"
import "os"
import "syscall"

func main() {
    // get the system's environment variables
    environment := os.Environ()

    // get a slice of the pieces of the command
    command := []string{"tmux", "new-session", "-s", "burrito"}

    err := syscall.Exec("/usr/local/bin/tmux", command, environment)
    if err != nil {
        fmt.Printf("%v", err)
    }
}

When this program is executed, it will replace itself with a new tmux session named burrito.

Go iota

Go has an interesting feature called iota. When declaring a list of constants, this keyword represents successive untyped integer constants.

const (
    foo = iota  // foo == 0
    bar = iota  // bar == 1
    baz = iota  // baz == 2
)

Anytime const is invoked, the counter resets.

const foo = iota  // foo == 0
const bar = iota  // bar == 0

This is a cool way to quickly define a list of integer constants, such as ‘true’ and ‘false’, for later use.