Sunday, August 21, 2016

How to Use Vendoring in Go

Vendoring is a way to put dependencies in a Go project without having to mess with the GOPATH. The idea is simple, that is to put the dependencies in a directory called "vendor".
awesomego/
|-- foo (this directory contains a library, i.e. non-main package)
|   `-- foo.go
|-- main.go (this is the main program)
`-- vendor (this is where the third-party libs live)
    `-- goini
        |-- goini.go
        |-- goini_test.go
        |-- LICENSE
        |-- README.md
        `-- testdata
            |-- test_expected.ini
            `-- test.ini

The project structure above has the following benefits.
  1. It can be used to build a library.
  2. It can be used to build an executable.
  3. It is go-gettable.
This is an example of using it in a standard Go workspace.
go-workspace/
`-- src
    `-- awesomego
        |-- foo
        |   `-- foo.go
        |-- main.go
        `-- vendor
            `-- goini
                |-- goini.go
                |-- goini_test.go
                |-- LICENSE
                |-- README.md
                `-- testdata
                    |-- test_expected.ini
                    `-- test.ini
To build it as a library:
GOPATH=`pwd` go install awesomego/foo
To build it as an executable:
GOPATH=`pwd` go install awesomego

Wednesday, August 3, 2016

Compile-Time Enum in Go

Unlike other languages, Go does not support enum. However, it is pretty straightforward to create something that behaves similar to enum. There are a lot of articles on the internet on how to create an enum in Go, which pretty much looks like below.
package main

import (
    "fmt"
)

type myType string

const (
    Foo myType = "foo"
    Bar myType = "bar"
)

func doSomething(t myType) {
    fmt.Println(t)
}

func main() {
    // baz := "baz"
    // This will result in compilation error:
    // "cannot use baz (type string) as type myType in argument to doSomething"
    // doSomething(baz)

    // However, this is allowed.
    doSomething("baz")
}
As you can see in the code above, calling doSomething("baz") does not result in a compilation error. To fix that, we can change the code to look like below.
package main

import (
    "fmt"
)

type myType string

const (
    Foo myType = "foo"
    Bar myType = "bar"
)

func doSomething(t *myType) {
    fmt.Println(*t)
}

func main() {
    // This will now result in a compilation error.
    // doSomething("baz")

    baz := myType("baz")
    doSomething(&baz)
}