Go
Some notes regarding the Go language. Some topics have graduated to their own page:
Setup
First things first. How to install the Go language in different OSes.
Fedora
You can either use dnf
directly and simply run
$ sudo dnf install golang-bin
This might not install the latest and greatest. If you want to use the most recent version, download it directly from https://golang.org/doc/install#install. If applicable, delete any previous /usr/local/go
directory with
$ sudo rm -rf /usr/local/go
Next, extract the archive file with
$ sudo tar -C /usr/local -xzf /home/foo/tmp/go-$VERSION.linux-amd64.tar.gz
And add /usr/local/go/bin
to the $PATH
. ### macOS
The best way to perform an attended installation of Go in macOS is to simply download the installer from https://go.dev/dl/ and running it.
Language design
Go doesn’t have sets
The Go language, notoriously, does not have1 some common data structures like sets. There are two main reasons for that:
- +Go does not have generics2
- Go relies on you writing your own data structures, generally
Go lacks generics, which prevent writing a … well, generic and efficient set implementation. Also, writing your own (non-generic) set with 3 The usual structure for a type map
s is quite straight-forward.T
is map[T]bool
, where the key is the element and the value is just a placeholder. For instance, for a int
set, we can add elements:
:= map[int]bool{1: true, 3: true}
s [1] = true // already presenvar t
s[2] = true // adds new element s
Some other techniques for maps replacing sets:
Set union
:= map[int]bool{1:true, 2:true, 3:false}
set_1 := map[int]bool{1:false, 2:false, 4:false}
set_2 := map[int]bool{}
set_union
for k, _ := range set_1{
[k] = true
set_union}
for k, _ := range set_2{
[k] = true
set_union}
.Println(set_union) fmt
Set intersection
:= map[int]bool{1:true, 2:true, 3:false}
set_1 := map[int]bool{1:false, 2:false, 4:false}
set_2 := map[int]bool{}
set_intersection for k,_ := range set_1 {
if set_2[k] {
[k] = true
set_intersection}
}
.Println(set_intersection) fmt
To convert a (map) set to an array:
:= make([]int, 0)
array := map[int]bool{1:true, 2:true, 3:false}
set_1
for k := range set_1 {
= append(array, k)
array }
.Println(array) fmt
CI
GitHub
A potential workflow for GitHub is to use GitHub Actions for Go. An example workflow file, .github/workflows/test.yml
, which runs go test
(see Testing in Go) and go vet
is:
on: [push, pull_request\]
name: Test
jobs:
test:
strategy:
matrix:
go-version: [1.14.x, 1.15.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
- name: Test
run: go test ./...
- name: Vet
run: go vet ./...
Containers
Minimal example
A minimal example of a Go container configuration for a web server running on port 8080
:
# Start from the latest golang base image
FROM golang:latest
# Add Maintainer Info
LABEL maintainer="Rui Vieira"
# Set the Current Working Directory inside the container
WORKDIR /app
# Copy go mod and sum files
COPY go.mod go.sum ./
# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download
# Copy the source from the current directory to the Working Directory inside the container
COPY . .
# Build the Go app
RUN go build -o main .
# Expose port 8080 to the outside world
EXPOSE 8080
# Command to run the executable
CMD ["./main"]
Reference
Conversions
How to convert a string
to byte
array?
The conversion is simple:
:= []byte("This is a string") b
Collections
Sort map keys alphabetically
If a map
contains string
keys, i.e. var myMap map[string]T
, we must sort the map keys independently. For instance:
:= make([]string, 0)
keys for k, _ := range myMap {
= append(keys, k)
keys }
.Strings(keys)
sortfor _, k := range keys {
.Println(k, myMap[k])
fmt}
Check for element
If we consider a collection, say, []string collection
, the way to check for an element already present is, for instance:
func existsIn(needle string, haystack []string) bool {
for _, element := range haystack {
if element == needle {
return true
}
}
return false
}
Templates
Check if variable empty
In a Go template you check if a variable is empty by doing:
{{if .Items}}<ul>
{{range .Items}}<li>{{.Name}}</li>
{{end}}</ul>
{{end}}
Looping over a map
Looping over the map var data map[string]bool
in a Go template:
{{range $index, $element := .}}
{{$index}}: {{$element}} {{end}}
Processes
Executing external processes
Executing an external process and directing input and output to Stdout
and Stderr
.
:= exec.Command("ls", "-1ao")
cmd .Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd:= cmd.Run()
err if err != nil {
.Fatalf("cmd.Run() failed with %s\\n", err)
log}
Testing in Go
Place the tests in your place of choosing, but keep the package declaration. Test functions should be parameterised as (t *testing.T)
and start with the prefix Test
, for instance:
package main
func TestFoo(t *testing.T) {
:= Foo(5, 5)
value // ... assertions
The test files themselves must have the suffix *_test.go
. Call the tests with go test
.
Output
Printing struct keys
To print a struct
along with its keys, we can use the Printf
switch as in the official documentation. That is,
.Printf("%+v\n", myStruct) fmt
Date and time
Check if a date is empty
If a date is unassigned, the .IsZero()
method can be used to check it
:= time.Time{}
a .IsZero() // This will be true a