Today I Learned

A Hashrocket project

7 posts about #go

Reading from standard in Go

Golang takes input from stdin with the Scan set of functions in the fmt package. These functions are, Scan, Scanf and Scanln.

var input string
fmt.Scan(&input)
fmt.Println(input)

The above snippet echos the input from stdin to stdout.

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.