Contents
Getting Started
What a stupid name. Unbelievable. Makes C and even Cpp/C# look like inspired branding. Search for "golang" pretty much always.
To install on Ubuntu and friends: sudo apt-get install golang-go
Note
|
The Ubuntu version could be quite old. Mine was 18 months old and missing important features. |
Here is a very nice online tutorial which is very helpful for getting started.
To just play around with the language almost interactively you can use a very nice on-line Go compiler/executer.
Here is a beautiful idea involving whitespace. Best of luck to them.
Here is a programming framework for robots and physical things. This looks pretty neat and perhaps useful for vision applications.
Essentials
/* Old school C comment styling works. */
// And so does C++ comment styling.
package main // Every file needs a "package" name. Maybe.
import "fmt" // To print, the "fmt" package is needed.
/* import ("os";"math") // This works too. */
var x = 3 // Variables can be declared outside functions. Global?
func main() {
x++ // Postfix only
fmt.Printf("%d\n",x) // Much like C's printf.
}
Semi-colons do not seem necessary. I think that semi-colons are generally quietly replaced by the lexer with new lines.
Seems like double quotes are quotes and apostrophes can’t be used interchangeably as in Python.
Reserved Words
Hard to find a definitive list.
src/pkg/go/token/token.go
& | ^ << >> &^ += -= *= /= %= &= |= ^= <<= >>= &^ && || <- ++ -- == <
> = ! != <= >= := ... break case chan const continue default defer
else fallthrough for func go goto if import interface map package
range return select struct switch type var
From go.vim
byte float float32 float32 float64 float64 int int16 int32 int64 int8 uint
uint16 uint32 uint64 uint8
break cap case chan close closed const contained continue default
defer else fallthrough false for func go goto if import uintptr
interface iota len make map map new nil package panic Panicln print
println range return select string struct switch true type var
Composing and Compiling
I was pretty annoyed that syntax highlighting was not ready to go out of the box, but something like this pretty well cured it:
wget -O ~/.vim/syntax/go.vim 'http://www.vim.org/scripts/download_script.php?src_id=11735'
echo 'au BufRead,BufNewFile *.go setfiletype go' >> ~/.vimrc
The general way to compile a Go program is:
$ go build myprogram.go
The go
executable has a lot of fancy things it can do helping or
replacing make.
build compile packages and dependencies
clean remove object files
doc run godoc on package sources
env print Go environment information
fix run go tool fix on packages
fmt run gofmt on package sources
get download and install packages and dependencies
install compile and install packages and dependencies
list list packages
run compile and run Go program
test test packages
tool run specified go tool
version print Go version
vet run go tool vet on packages
Binary Size - Yikes!
At this time (2014) the Go compiler creates whopping huge files even for very trivial "hello world" kinds of programs.
$ ls -l hello* ; cat hello.go
-rwxr-xr-x 1 xed xed 1267721 Jan 21 17:04 hello
-rw-r--r-- 1 xed xed 71 Jan 21 17:04 hello.go
package main
import "fmt"
func main() { fmt.Printf("hello, world\n") }
There are a couple of reasons for this. First this binary is static. I think C programs compiled statically would also be frighteningly large if not quite this big. Also Go needs to include a complete garbage collector, concurrency management, and all its other fancy stuff. Compare the executable size to a small Python script and Python itself, for example. There is some work being done to address this issue. Hopefully this will be an area of improvement. There is also something called UPX which can make executable binaries into self-extracting compressed binaries. Apparently Go binaries don’t quite work, but again, that is being worked on. I got about a 1:4 reduction using bzip2 so there probably is a solution.
Comments
Go has many fancy core utilities that do helpful things. One is
godoc
which produces some kind of documentation about packages.
Although optional, to get this to all work you need to make your
package comments fit a particular format.
/*
The example package provides a library for
discussing examples. I'm just making this up of course.
In this example, godoc will do the formatting.
Don't do anything fancy like ******** or rely on fixed
width ascii art, etc. Best to use complete sentences
and assume you're writing a guide. Any comment preceding
a top level declaration serves as a doc comment. Every
exported (capitalized) name should have one.
*/
// Example function does some great stuff while serving
// as an example. Note how this doc comment starts with
// the function name (Example). This is apparently good
// practice.
func Example(some string) int {
Variables And Types
If a variable starts with a capital letter, then it is visible to clients of the package.
var Visible string
var _NotVisible string
var notvisible string
This means that if you’re dealing with a lower case variable, it will
not be confused for something from another package. So in Python, you
can define pi=3.141
and then somewhere have from math import pi
and there will be confusion. Go does not ever have this problem.
Types
- bool
-
true
orfalse
are the keywords of interest. - byte
-
alias for uint8
- complex{64,128}
- error
-
(Is this a type?)
- float{32,64}
- int, int{8,16,32,64}
- uint, uint{8,16,32,64}
- string
-
See import "strings".
var i int
var hi,low int
var red,black int = 1,2
var heads = false
var first,last = "Bert", "Russell"
var u uint = uint(hi) // Casting works on some things.
You can make your own type with the type
declaration.
type Coin bool
There is also a concept of an "interface" type which is basically a named collection of methods. This type can hold any value that implements all of the methods. This is to provide the same kind of features that object oriented languages have (I think).
Short Declaration Assignment
For some reason Go uses make
's :=
(non recursive) assignment
syntax for making implicitly typed assignments within function blocks.
package main
import "fmt"
const alwayson = true // No type needed/allowed.
var outside bool = true // Must use `var` keyword.
func main() {
inside := 1 // Type not needed.
}
for Loop
The for
statement is pretty much like C’s. When contrasting C
syntax, seems like a common Go theme is to not require the parentheses
(of an if
or for
statement) but to require the braces.
The for
keyword does everything a "while" statement would do (so
there is not one of those). If you leave out the setup completely for
{runs_forever}
, then the loop runs forever.
// for a,b,c { looped_clause }
// a. Initial condition
// b. Do the loop if true
// c. Do this every iteration. Strangely redundant with looped_clause.
for i := 0; i < 10; i++ {
sum += i
}
x := 0
for x<100 { // Go's "while" syntax. (No semicolons.)
x++
fmt.Println(x)
}
There is a special version of the for
loop which uses the range
keyword.
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) }
for _, v := range pow { fmt.Printf("%d\n", v) } // Skip index with _.
} // Value can also be skipped with _.
if Conditional
b:= true
if b { // Or: if b == true
fmt.Println("Yes!")
}
if b = !b; b { // 1. Assignment (setup, like `for`); 2. Condition
fmt.Println("No.")
} else {
fmt.Println("Yes.")
}
Structs
Somewhat like C structs. Access components using a dot.
package main
import "fmt"
type Customer struct {
first_name string
last_name string
}
func main() {
C:= Customer{"Frank","Ramsey"}
fmt.Printf("Dear %s,", C.first_name)
}
Struct values can be omitted; they then default to zero. Not sure if that mechanism works for strings and bools and what they’d default to.
package main
import "fmt"
type Car struct {
cc float32 // Defaults to 0
fwd bool // Defaults to false
name string // Defaults to empty string
}
func main() {
ferrari:= Car{name:"F150"} // Can fill in some fields or none.
fmt.Println(ferrari)
}
Pointers
Another feature similar but different to C is the use of pointers.
-
Memory is automatically garbage collected.
-
There is no pointer arithmetic.
-
Use the address operator
&
to make a pointer. -
Use the dereference operator
*
to turn an address back into a thing. -
Pointers to structs can use dot notation for components just like full structs.
n:=44
fmt.Println(&n) // Produces address thing (like `0x10500188`).
nova:= new(int) // Makes a new int sized pointer, zeroed.
var nova *int = new(int) // Same as above.
Arrays
Declare an array of integers and load it up:
var pow= []int{1,2,4,8,16,32,64,128}
var xyz [3]float32
xyz[0], xyz[1], xyz[2] = -2.2, 3.2, 0
// Or...
xyz := []float32{-2.2,3.2,0}
Slices
Arrays support slices which are pretty similar to Python’s.
myarr[lo:hi+1] // lo starts at 0; hi is specified +1 so for 2, say 3 {0 1 2 3}
myarr[same:same] // Empty slice.
myarr[lo:lo+1] // Single element
However, some fancy Python stuff is a little weirder than it is in
Python. (Of course as a Python programmer, I’m biased.)
For example, slices with zero values can be ==
to nil
, a reserved
word.
See this tutorial page.
Maps
A little wacky, but not even close to STL wacky.
This makes an empty, but fillable map.
package main
import "fmt"
var m map[string]int // This just says what it is - no allocation.
func main() {
m= make(map[string]int) // Allocation needed to prevent runtime errors...
m["Three"] = 3 // ...when filling the empty map.
fmt.Println(m["Three"])
}
Syntax for using map literals to initialize a map:
zip := map[string]int{
"san diego": 92111,
"boston" : 02134,
"fly creek": 13337,
}
m_t = map[string]int{} // To initialize an empty map.
Maps support all the good stuff:
-
m[key] = val
Assignment or change value. -
x= m[key]
Retrieval. -
delete(m,key)
Remove item. -
x,ok= m[key]
Hereok
is eithertrue
orfalse
depending on key’s presence.
Use range
to iterate over the contents of a map:
for key, value := range m {
fmt.Println("Key:", key, "Value:", value)
}
Here’s an official example:
Functions
Functions are generally defined with
-
Keyword
func
(required) -
"Method receiver" argument list in paren (optional)
-
Function name (required)
-
Function parameter list in paren (optional)
-
Return type (not sure if required)
The "method receiver" is a way to bind the function to a user defined
type. This allows you to call this function on variables of that type
using a kind of object oriented syntax. The user defined type is
usually a struct
which allows for very oo behavior, but it can be
anything you define. For example:
type Coin bool
func (this Coin) Obverse() Coin {
return !this // I chose the name `this`. There is no `this` keyword.
}
func main() {
var p Coin
p = false
fmt.Println(p.Obverse())
}
Note that the method receiver can also be a pointer to one of the package defined types. This can make it more efficient to pass objects to the method. Also, it’s important to use pointers if you want your object to be mutated. If your object will just be used in the method but not change, then you can send in a direct value. If the object needs to be changed, then use a pointer. See this example for details.
Functions can be values too (because this language is pretty sane).
package main
import "fmt"
func main() {
p := func(s string) {fmt.Println(s)}
p("A much less annoying print statement!")
}
There is some kind of syntax that provides for a variable number of arguments. It seems to be something like this using ellipsis:
func Printf(format string, v ...interface{}) (n int, err error) {}
The function name init()
is special and can be used to set up
special things for a package.
Switch
Switches are similar to C. No parens and the condition expression can be preceded with a setup expression (separated by semi-colon).
switch k {
case 44:
fmt.Print("Forty-four")
case 33:
fmt.Print("Thirty-three")
default:
fmt.Print("No idea, mate.")
}
Another way to use switches is to leave the condition expression empty
so that it will default to true
. Then have the case expression be a
test. This can be like a big if/else chain.
switch {
case level < 4:
fmt.Println("Mild.")
case level < 7:
fmt.Println("Moderate.")
default:
fmt.Println("Severe!")
}
Working With Files
To read files the following will work but it will read the entire file into memory:
import io/ioutil
somewords,read_err:= ioutil.ReadFile(FN)
if read_err != nil {
fmt.Println("There was an error accessing: "+FN)
return
}
The good thing about this method is that it works for versions as low as 1.03. If you want to read line by line, make sure you have a later Go (1.2 works) and try something like this:
import "bufio"
scanner:= bufio.NewScanner(os.Stdin)
for scanner.Scan() {
somewords:= scanner.Text()
linewordlist := strings.Fields( string(somewords) )
}
This reads a line of text and then makes an array of the whitespace-separated words it finds. This example also shows how to input from standard input. Note that I’m not listing all the extra imports and any other code that may actually put this to use.
Errors
An error is anything that can describe itself as an error string. The
built in type error
is pretty much automatically defined by
something equivalent to:
type error interface {
Error() string
}
Wikipedia says "returning a result, err pair is the standard way to handle errors".
See this sample.
Concurrency
Instead of coordinating a shared state among many distributed processes, Go seems to want to use "channels" to pass values around as needed. This ensure that the values are never actively shared by separate threads of execution. Instead of having a global value X that all processes mess with erratically, processes are encouraged to send values to each other. R. Cox says of good Go programming , "Do not communicate by sharing memory; share memory by communicating." This way of thinking is similar to using Unix pipes for sharing state instead of having both pipe connected programs share the exact same memory.
Importables
See the official package documentation for details.
-
archive -
-
compress -
-
crypto -
-
flag - Seems to be argparse kind of thing.
-
fmt -
fmt.Println
,fmt.Printf
,fmt.Fprintf
-
hash -
-
image -
image.NewRGBA
official docs -
io -
-
log -
-
math -
-
math/big -
-
net -
-
net/cgi -
-
net/http -
http.Request
,http.ResponseWriter
,http.ListenAndServe
See this example to see how to write a web server. -
os -
os.Stdout
,os.Getenv
-
path -
-
regexp -
-
sort -
-
strings - Most of the sensible stuff: import "strings"
-
time -
time.Now
,time.After
,time.Second
-
unicode -
unicode.Is
$ ls /usr/share/go/src/pkg/
archive bufio builtin bytes compress container crypto database debug encoding
errors expvar flag fmt go hash html image index io log math mime net os path
reflect regexp runtime sort strconv strings sync syscall testing text time
unicode unsafe
Example
Here’s my simple bin packing example in Go.
package main
import ("fmt";"math/rand";"time")
const bincount int= 250000
const binsize int= 100
const maxitem int= 70
func next_item() int {
return (rand.Intn(maxitem))
}
func main() {
rand.Seed( time.Now().UTC().UnixNano())
var bins= [bincount]int {}
for i:=0;i<bincount;i++ {bins[i]= binsize}
var still_room bool= true
var item int
for still_room == true {
item= next_item()
for i,_ := range bins {
if bins[i] >= item {
bins[i] -= item
break
}
if i == bincount-1 {
still_room= false
}
}
}
sum := 0
for _,i:=range bins{sum+=i}
fmt.Println(sum)
}