Go Programming
Related notes: Interesting Golang libraries
Packages #
In Go, programs start running in package main
. Package names are defined by
the last element of the import path: import math/rand
has files which begin
with the package rand
. Packages consists of a bunch of .go
files.
Package identifiers (functions, variables, struct and other data), may be used
in other packages, with a few exceptions. Go allows only exported identifiers to
be called after the package import. An exported identifier is any identifier
which the first character starts in UPPER CASE
. Any identifier which starts
with a lower case
letter is not exported.
Exported identifiers can be thought of public
and private
we see in other
languages. This approach allows us to separate public API by using upper case
character from private logic.
Private identifier within a package may be referenced within its package.
Functions #
A function can have 0 or more arguments. All arguments must be typed: x int, y int
, when 2 or consecutives arguments share the same type, arguments may be
defined as so: x, y int
.
Functions can return 0 or more number of results: return x, y
. Function return
values may be named, and must be defined after the function declaraction and
before the beginning {
import "fmt"
func foobar(x, y int) (z int){
z = x * y
return
}
func main(){
x := foobar(3, 3) // should return 9
fmt.Println(x)
}
9
The empty return will return the z value. Named return values should be used to document the meaning of the return values. Named return values should be used on short functions, as named values in large functions may become confusing.
Arrays #
An array can be defined by [x]T
of n values of type T. In GO, we cannot
defined an array size dynamically on run time, thus the following will not work:
import "fmt"
func array(size int) ([]int){
var arr[size]int
for i := 0; i < size; i++ {
arr[i] = i * 2
}
return arr
}
func main(){
fmt.Println(array(10))
}
But the following will work:
import "fmt"
func array() ([10]int){
var arr[10]int
for i := 0; i < 10; i++ {
arr[i] = i * 2
}
return arr
}
func main(){
fmt.Println(array())
}
[0 2 4 6 8 10 12 14 16 18]
Slices #
Slice expressions construct a substring or slice from a string, array, pointer to array, or slice.
Arrays are convenient but limiting. Sizes are fixed and no way of resizing. Go
provides slices
, which can be dynamically reallocated. Like Python, Go slices
can be formed by specifying slices with a low and high bound:
import "fmt"
func array() (*[10]int){
var arr[10]int
for i := 0; i < 9; i++ {
arr[i] = i * 2
}
return &arr
}
func main(){
arr := array()
fmt.Println(arr[0:5])
fmt.Println(arr[0:2])
/* https://golang.org/ref/spec#Address_operators */
arr1 := array()[0:5]
x := arr1[1:2]
x[0] = -1
fmt.Println(arr1, x)
}
Slices are references to arrays #
A slice describes a section of an underlying array, it does not store any
data. If X is an array and Y a slice of x[0:1]
, changing index 0 will change
all the value of slices that share the same underlying array.
import "fmt"
func main() {
x := [6]int {1, 2, 3, 4, 5, 6}
y := x[0:2]
fmt.Println(y, x)
y[0] = 10
fmt.Println(y, x)
}
Length and capacity #
A slice has a capacity and length. The length is the number of elements the current slice has, and the capacity is the number of elements the underlying slice has counting from the first element of the slice
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Printf("Slice: %v\n", slice)
fmt.Printf("Cap of slice (%p): %d\n", slice, cap(slice))
fmt.Printf("Len of slice (%p): %d\n", slice, len(slice))
subslice := slice[0:5]
fmt.Printf("Cap of slice (%p): %d\n", subslice, cap(subslice))
fmt.Printf("Len of slice (%p): %d\n", subslice, len(subslice))
/* extend subslice */
extended := subslice[:10]
fmt.Printf("Cap of slice (%p): %d\n", extended, cap(extended))
fmt.Printf("Len of slice (%p): %d\n", extended, len(extended))
shrink := subslice[:2]
fmt.Printf("Cap of slice (%p): %d\n", shrink, cap(shrink))
fmt.Printf("Len of slice (%p): %d\n", shrink, len(shrink))
// drop first 2 items
subslice = subslice[2:]
fmt.Printf("Cap of slice (%p): %d\n", subslice, cap(subslice))
fmt.Printf("Len of slice (%p): %d\n", subslice, len(subslice))
fmt.Printf("slice: %v\n", slice)
fmt.Printf("subslice: %v\n", subslice)
fmt.Printf("extended: %v\n", extended)
fmt.Printf("shrink: %v\n", shrink)
}
CURRENT Creating dynamically-sized slices #
Dynamically-sized slices can be created with make
import "fmt"
func main(){
arr := make([]string, 5) /* slice of strings of length 5 */
fmt.Printf("Cap: %d, Len: %d, %v", cap(arr), len(arr), arr)
arr[0] = "Hello, world"
fmt.Println(arr)
}