The Go Language

Getting Started

First, download go for your machine, or using a package manager. There's installation instructions if you want to do any additional configuration.

If you already have Go installed on your computer, you can use it to install other versions of Go.

go install golang.org/dl/go1.17@latest && go1.17 download

Be sure to remember to prepend ~/sdk/go1.17/bin to your shell's command search path, as this is where the binary executable will end up being installed in.

For the latest version of Go, on the development branch, you can follow a similar process using gotip.

go install golang.org/dl/gotip@latest && gotip download

You can actually check out the official tour of Go, as well, which you can run locally.

This will install the tour in $GOPATH/bin.

Your First Program

A heads up, oddly enough, the type comes after the variable name, something I learned from reading an article on Go's declaration syntax

Strings

Creating a string representation of an interface:

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("The person named %v is %v years old", p.Name, p.Age)
}

Packages

Programs in go are made up of multiple packages, and will run starting from the code defined in the main package.

Slices

Slices are a bit tricky, it is explained very well in Rob Pike's blog post on slices.

Also, felt this was worth writing down for my own safe-keeping:

It is idiomatic to use a pointer receiver for a method that modifies a slice.

--Rob Pike

len()

For locally defined slices the length is cached, so there is no runtime overhead for calls to len(a) provided that a is not defined beyond the local scope. For globally defined slices, the length is not cached, as its length can be modified elsewhere, which requires it to be re-evaluated each time a call to len(a) is made 1.

Arrays

Arrays are used less often than slices, but sometimes you find yourself in a situation where you'd like to create a fixed size array, using the values contained within a slice. Here is the idiomatic way for you to do precisely that:

var fixed [3]int

sliced := []int{1, 2, 3, 5, 8, 13}

copy(fixed[:], sliced)

This syntax takes advantage of the faxt that copy will only copy the minimum of len(src) and len(dst) bytes.


Scanners

If you need to read a file in line by line, the most idiomatic way to do so is by using bufio.Scanner

file := os.Open("file.txt")
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var txtlines []string

for scanner.Scan() {
    txtlines = append(txtlines, scanner.Text())
}

file.Close()

for _, eachline := range txtlines {
    fmt.Println(eachline)
}

JSON

Unmarshalling JSON formatted data

Make an HTTP request, receive JSON in the body of the response, and unmarshall that JSON into a Go struct named result:

response, err := http.Get("example.com/api/gimmejson")
if err != nil {
    return
}
defer func(Body io.ReadCloser) {
    err = Body.Close()
    if err != nil {
        return
    }
}(response.Body)

data, err := io.ReadAll(response.Body)
if err != nil {
    return
}
err = json.Unmarshal(data, result)
return

Input/Output

os.Stdin and os.Stdout are the standard input and output streams, which means they can be passed in to functions like os.Read and os.Write just as you would with any other parameter.

Installing Go Modules

You can install Go code using the install subcommand.

# Option 1
go install example.com/user/hello@latest

# Option 2
go install .

# Option 3
go install

For convenience, go commands accept paths relative to the working directory, and default to the package in the current working directory if no other path is given. So in our working directory, the commands shown above are all equivalent:


Defer, Panic, and Recover

There's an interesting article about callback functions using defer, but I'll leave that for another time.


Vim Plugin

If you want to edit your Go projects in Vim, there's a very healthy ecosystem to support you.

" Install the libraries needed for `vim-go`
:GoInstallBinaries
" Getting help
:help vim-go

I've included some useful commands below:

" Run the code in the current buffer
:GoRun

" Compile the code
:GoBuild

" Install the coe
:GoInstall

" Test the code
:GoTest

" Test a single function
:GoTestFunc

" See dependencies of the current package
:GoDeps

" See all source files in cwd
:GoFiles

" Rename an identifier
:GoRename

" Format the document according to the go style guide
:GoFmt

" Resolve all needed package imports & remove all unused packages
:GoImports

" Import the package `math` #study #rise&grind
:GoImport math

" Drop the package `math` #jk2cool4school
:GoDrop math

" Pull up documentation for the function `Printf` package `fmt`
:GoDoc fmt Printf

Style

Below are some notes I took while reading "The Go Programming Language"

The letters of acronyms and initialisms like ASCII and HTML are always rendered in the same case, so you might want to call a function htmlEscape, HTMLEscape, or escapeHTML, but should avoid calling it escapeHtml.

Syntax and Semantics

A declaration names a program entity and specifies some or all of its properties. In Go, the four main types of declarations are var, const, type, and func, but every .go file begins with a package declaration, followed by import declarations, and finally, zero-or-more package-level declarations.

In Go, there is no such thing as an unitialized variable. If a value is not provided for a variable at its declaration, the variable will have its value initialized to the zero-value corresponding to that variable's underlying type.

The := operator performs short variable declaration. Unlike the = operator, which performs assignment, the := operator performs declaration, which is distinct from assignment.

The zero value for a pointer of any type is nil. If there is a variable p, which is a pointer type variable, the test p != nil is true if p points to a variable. Two pointers are equal if and only if they point to the same variable, or are both equal to nil.

The expression new(T) creates an unnamed variable of type T, initializes it to the zero-value of type T, and returns its address, which is a value of type *T.


Functions

Linked List

Formatting Numbers

Note: The example below was written mainly just for practice. github.com/dustin/go-humanize provides a far more robust implementation of this functionality.

File I/O

In the examples below, assume that file has already been opened and is ready to be used.

Imports

import (
    "bufio"
    "bytes"
    "io"
    "os"
)

Templates

To do

Consider the following template file file.html, located within the directory tmpl:

<p>Hello, {{.Name}}! Welcome to {{.Location}}.</p>

The .Name and .Location variables can be replaced in a Go file using the template package:

type Doc struct {
	Name     string
	Location  string
}



func main() {
	t, _ := template.ParseFiles("tmpl/file.html")
	fmt.Println(dr.Name)
	t.Execute(os.Stdout, dr)
}

The output should be:

<p>Hello, Doctor! Welcome to GitHub Hospital.</p>

Interfaces

To do

An interface defines a set of methods that, if implemented by a type, cause that type to be a valid instance of that interface.

Concurrency

channels, go routines,

Networking

Todo.

Reading/Writing

Todo.

Printing

Discovered in the article Effective Slices:

For maps, Printf and friends sort the output lexicographically by key.

When printing a struct, the modified format %+v annotates the fields of the structure with their names, and for any value the alternate format %#v prints the value in full Go syntax.

type T struct {
    a int
    b float64
    c string
}
t := &T{ 7, -2.35, "abc\tdef" }
fmt.Printf("%v\n", t)
fmt.Printf("%+v\n", t)
fmt.Printf("%#v\n", t)
fmt.Printf("%#v\n", timeZone)

Produces the following output:

&{7 -2.35 abc   def}
&{a:7 b:-2.35 c:abc     def}
&main.T{a:7, b:-2.35, c:"abc\tdef"}
map[string]int{"CST":-21600, "EST":-18000, "MST":-25200, "PST":-28800, "UTC":0}