Golang
- Tags
- language
Go is a relatively new language from the venerated Rob Pike and other legends from the age of bell labs and early Unix. It values consistency and explicitness at the cost of verbosity and an unconventional approach to building highly concurrent applications.
Syntax
Comments
The go language supports both c style inline and multi-line comments.
// Here's an inline comment
/* Here's a multiline comment */
Modules
A module is a collection of packages.
The namespace for a module is determined by the go.mod
file in the root of the
project. This file is generated by the go mod init
command.
For example, a directory layout like below that has a module, defined in go.mod
,
of "github.com/mohkale/projectFoo"
uses package projectFoo
in the files in the
root of the project (example: main.go
). However in foos
sub-package the files use
package foos
and need to be imported through "github.com/mohkale/projectFoo/foos"
.
projectFoo go.mod main.go foos/ foo_a.go foo_b.go
Packages
Like java each src code file should begin with a package
declaration. This
declares the namespace of public functions and constructs in the package.
A special package name of main tells the go compiler to create an executable
from the package instead of a library to be imported. When doing so you must
define a main
function taking no arguments that runs the executable.
By design a package has access to any identifiers defined within it including in
another file. Packages can also access identifiers in other packages but only if
their marked as public by beginning with an uppercase letter. Therefore foo
is
private but Foo
is public.
Note: as a consequence this means any functions or structs you import from another
package are always called with capital letters.
Imports
Imports go at the top of the file after the package declaration.
import "fmt"
// you can wrap the imports in parentheses to specify multiple imports
import (
"io"
"sys"
)
You can also specify an alternative prefix for an imported package.
import shortAndSweet "github.com/mohkale/someReallyDumbLongProjectName"
Or remove the prefix altogether, allowing you to access identifiers for an imported package as if they were defined in the current package.
import . "net"
Variables and Types
Go has a rich set of builtin types including:
- byte
- rune (unicode code point)
- string
- int
- uint
- floats
- complex
Basics
There are two syntax's for declaring variables.
var foo string = "Hello world"
var bar = 1234 // Infers type
foo := 1234 // alternative syntax
Go is unlike most other languages where if you declare a variable but don't assign it a default value, it will be assigned a default zero-value. This follows the same vein as C where if you allocate memory for a struct it normally has some value in that new memory even if you haven't actively assigned it yet.
var baz int // #=> 0
var bag string // #=> ""
As a form of syntax sugar you can defer the type definition to the last identifier in a list of them and all variables will be declared with that type.
var bag, bam, boom float64
Pointers
Go supports pointers as a form of pass by reference.
var bagPointer *float64 = &bag
For the most part you can use pointers as the underlying value, there's no special syntax (like C) to access the fields of a struct pointer.
You can also dereference a pointer using the * operator.
var bagValue = *bagPointer // copy of bag
Functions
Are declared with the func
keyword and the same rules for type declarations apply
to them.
func fooBar(foo string, bar int) bool {
fmt.Println("f:", foo, "b:", bar)
return true
}
Go supports functions as first class objects so you can create anonymous functions by omitting the identifier of the function and closures.
var myFunc func(int) int = func(x int) int {
return x + 10
}
fmt.Println(myFunc(5)) // #=> 15
The ...
ellipse syntax can be used to support variadic arguments.
func fooBarBaz(foo string, bars ...int) {
fmt.Println("f:", foo, "b:", bars)
}
fooBarBaz("hello world", 1, 2, 3, 4, 5, 6)
Arrays/Slices
The only collection type built-into go is the array.
You declare arrays be prefixing the type of the array with the capacity.
var shoppingList [3]string
shoppingList[0] = "apples"
shoppingList[1] = "oranges"
shoppingList[2] = "pears"
// you can also use a composite literal to specify the fields in 1 expression.
var inlineShoppingList = [3]string{"apples","oranges","pears"}
However you'll rarely be using arrays by themselves. Go is implemented as a pass by value language, therefore arrays are copied in their entirety when passed to functions.
To get around this, you'll more often than not be using slices. A slice is a subsection of an array that's defined with both a length and a capacity. The length is how many items the slice has, the capacity is how many the underlying array can hold if need be.
var shoppingSlice []string = shoppingList[:] // A slice
fmt.Println(len(shoppingSlice)) // #=> 3
fmt.Println(cap(shoppingSlice)) // #=> 3
Operations on slices work much like low-level C.
// You can specify an upper and lower bound for a slice just like python.
var shoppingSlice2 []string = shoppingList[0:1]
fmt.Println(len(shoppingSlice2)) // #=> 1
fmt.Println(cap(shoppingSlice2)) // #=> 3
// You can reslice a slice and delete elements from a slice by just
// defining a newer slice without some leading elements.
shoppingSlice = shoppingSlice[1:] // #=> ["oranges", "pears"]
fmt.Println(len(shoppingSlice2)) // #=> 2
fmt.Println(cap(shoppingSlice2)) // #=> 2
The aforementioned arrays are declared at compile-time and pushed onto the stack.
You can't declare an array with a length we only know at runtime like this. Instead
you need to use the make
method to allocate the array on the heap
.
var capacity = 10
var length = 5
// this create a slice of type string that can take upto 10 strings and is
// initialised with 5 empty strings. If capacity isn't provided, it equals
// length.
var myArray = make([]string, length, capacity)
Hashmaps
Tooling
go fmt
The go fmt command reads go code and uses it to build document for a go project. Some file in each package should have a documentation comment at the start of it (to describe the package). Similarly each public struct or function should also have some docstring describing its usage.