Inhaltsverzeichnis

Go Programming Language Tips

Setup

Download Go source:

cd /usr/local
hg clone -r release https://go.googlecode.com/hg/ go

Build Toolchain:

cd go/src
./all.bash

Add Go tools to PATH by creating /etc/profile.de/go.sh:

#!/bin/sh
export PATH="$PATH:/usr/local/go/bin"
export GOROOT=/usr/local/go

Go Syntax Highlighting for your editor at http://go-lang.cat-v.org/text-editors/

Go Syntax Highlighting for your dokuwiki at http://rosettacode.org/wiki/User:MizardX/GeSHi_Go.php (Doesn't work with 2009-12-25c „Lemming“)

Updating Go is described here

ARM5 (Sheevaplug) specific

Build Crosscompiler on x86 for ARM5

Export the following variables before running src/all.bash:

export GOROOT=$(pwd)
export GOHOSTARCH=386
export GOHOSTOS=linux
export GOARCH=arm
export GOOS=linux
export GOARM=5

Hello World

package main
import "fmt"
 
func main() {
    fmt.Printf("Hallo  Süße!\n")
}

Build & run:
x86: 8g hello.go && 8l -o hello hello.8 && ./hello

arm: 5g hello.go && 5l -o hello hello.5 && ./hello

For Printf see pkg/fmt/

Command Line Arguments

Use the os.Args slice. Source

Exit Code

Use os.Exit().

return in main() only works without any argument, which results in 0 as exit code (tested).

Standard Streams

FIXME

Variable Declaration

package main
import "fmt"
func main() {
    var i,j int                         // 2 ints, autoinitialized to zero value
    fmt.Printf("%d %d\n", i, j)         // 0 0 
 
    var k,l,m,n= true, 0, 2.6, "Hello"  // missing types default to:
    fmt.Printf("%T %T %T %T\n",k,l,m,n) // -> bool int float64 string
    fmt.Printf("%v %v %v %v\n",k,l,m,n) // -> true 0 2.6 Hello
    fmt.Println(k,l,m,n)                // -> true 0 2.6 Hello
 
    o,p:= false, "World"                // short form: no type but initializers:
    fmt.Printf("%T %T\n", o, p)         // -> bool string
    fmt.Println(o,p)                    // -> false World
}

more

Arrays

a := [...]int{0, 1, 2, 3}           // an array created literally
a := [4]int                         // create a zeroed array (?)
package main
import "fmt"
func main() {
    //var ia= [...]int{47, 11}      // Create an array literal
    ia:= [...]int{47,11}            // Create an array literal - short form
 
    for i, v := range ia {          // Loop through an array
        fmt.Printf("%d %d\n", i, v)
    }
 
    var ib [3]int                   // Create arrays with ZEROED elements
    var ic [2]int
    for _, v := range ib {          // '_' means key not used
        fmt.Printf("%d \n", v)      // -> 0 0 0
    }
 
    //i=0                           // illegal, i not defined outside loop
    //ib = ia                       // illegal, different len => different types
    //ib[3]=9                       // illegal, index out of bounds
    //fmt.Println(ia == ic)         // illegal, no == operator for array
 
    ic= ia                          // copy BY VALUE
    ia[0]= 36
    fmt.Println(ia, ic)             // -> [36 11] [47 11]
 
    //i:=3
    //ib[i]=9                       // panic => runtime index check :-)
}
  • The length of the array is part of its type and cannot grow
  • Arrays are real types
  • Arrays are copied by value :!:
  • A Pointer to an array is possible (unlike in C where the pointer represents the array)

Slices

s := []int{0, 1, 2, 3}                  // a slice created literally
s := make([]int, 4)                     // create a zerored slice
len(s) // get number of items in slice
cap(s) // get actual slice capacity
package main
import "fmt"
func main() {
    a:= [...]int{0, 1, 2, 3}            // an array to play with
    sa:= a[:]                           // Create slice from whole array
    sb:= a[:2]                          // Create slice from first part
    sc:= a[2:]                          // Create slice from last part
    fmt.Println(sa, len(sa), cap(sa))   // -> [0 1 2 3] 4 4
    fmt.Println(sb, len(sb), cap(sb))   // -> [0 1] 2 4(!)
    fmt.Println(sc, len(sc), cap(sc))   // -> [2 3] 2 2
 
    sa[0]=6                             // all slices point to the same array:
    sb[1]=7                             //
    sc[0]=8                             //
    a[3]= 9                             //
    fmt.Println(a, sa, sb, sc)          // -> [6 7 8 9] [6 7 8 9] [6 7] [8 9]
 
    //sb[2]=7                           // panic, although cap is 4!
 
    sb= sa                              // A copy points to the same array:
    fmt.Println(a, sa, sb)              // -> [6 7 8 9] [6 7 8 9] [6 7 8 9]
    sb[0]=0                             //
    fmt.Println(a, sa, sb)              // -> [0 7 8 9] [0 7 8 9] [0 7 8 9]
 
    // fmt.Println(sb==sa)              // invalid, works only with nil
 
    sc= append(sb, 5)                   // append() can create new array:
    fmt.Println(sa, sb, sc)             // -> [0 7 8 9] [0 7 8 9] [0 7 8 9 5]
    sa[1]= 1                            //
    sb[2]= 2                            //
    fmt.Println(sa, sb, sc)             // -> [0 1 2 9] [0 1 2 9] [0 7 8 9 5]
}
  • Slices are copied by value but the internal arrays are copied by reference :!:
  • Slices have a length (number of items) and a capacity (length of underlying array(?))
Appending to a Slice results in a new slice. The new slice may point to a different array than the original slice.

more

Objects

Copying Objects

type Point struct {
    x, y int
}
 
func main() {
    p:= Point{}
    fmt.Println(p)                      // -> {0 0}
 
    c:= p
    p.y= 1
    c.x= 2
    fmt.Println(p, c)                   // -> {0 1} {2 0}
}
Objects are copied by value

Methods

/** A method which has a copy of its object as receiver: */
func (pt Point) SetWithVal(x, y int) {
    pt.x= x
    pt.y= y
}
 
/** A method which has a pointer to its object as receiver: */
func (pt *Point) Set(x, y int) {
    pt.x= x
    pt.y= y
}
 
func main() {
    p:= Point{}
 
    /* invoking both methods on an object: */
    ov:= p
    ov.SetWithVal(1, 2)                 // -> SetWithVal operates only on copy!:
    fmt.Println(ov)                     // -> {0 0}
    ov.Set(3, 4)                        // -> Set works as expected:
    fmt.Println(ov)                     // -> {3 4}
 
    /* invoking both methods on pointer to object: */
    op:= &p
    op.SetWithVal(5, 6)                 // -> SetWithVal operates only on copy!:
    fmt.Println(op)                     // -> &{0 0}
    op.Set(7, 8)                        // -> Set works as expected:
    fmt.Println(op)                     // -> &{7 8}
 
    /* As expected, canges to the pointer change also the object pointed to: */
    fmt.Println(p)                      // -> {7 8}
}
  • In order to really work on the object, the receiver of the method must be a pointer to the object, otherwise the method operates ony on an (anonymous) copy.
  • Invoking methods on pointers to objects has the same syntax and work the same as invoking the method directly on the object.

Interfaces

type Point struct {
    x, y int
}
 
func (pt Point) SetWithVal(x, y int) {
    pt.x= x
    pt.y= y
}
 
func (pt *Point) Set(x, y int) {
    pt.x= x
    pt.y= y
}
 
type SetWithVal_i interface {
    SetWithVal(x, y int)
}
 
type Set_i interface {
    Set(x, y int)
}
 
func main() {
    var isp Set_i
    var isv SetWithVal_i
    fmt.Printf("%T %T\n", isp, isv)     // <nil> <nil>
 
    o:= Point{}
    isv= o                              // isv is an independent COPY of o:
    fmt.Printf("%T\n", isv)             // -> main.Point
    o.x= 9                              // but the copy
    isv.SetWithVal(1, 1)                // can't be modified via isv:
    fmt.Println(o, isv)                 // -> {9 0} {0 0}
 
    o= Point{}                          // reset to {0 0}
    isv= &o                             // isv now is a POINTER(!) to o:
    fmt.Printf("%T\n", isv)             // -> *main.Point
    o.x= 9                              // updates to object are seen by isv
    isv.SetWithVal(2, 2)                // but object can't be modified via isv:
    fmt.Println(o, isv)                 // -> {9 0} &{9 0}
 
    o= Point{}                          // reset to {0 0}
    //isp= o                            // Err! Set_i.Set needs pointer receiver
 
    isp= &o                             // isp now points to o:
    fmt.Printf("%T\n", isp)             // -> *main.Point
    isp.Set(3, 3)                       // object can be modified via interface
    o.y= 4                              // and vice versa:
    fmt.Println(o, isp)                 // -> {3 4} &{3 4}
}
An Interface can store any value that implemts it. This can be a value or a pointer to a value.

The only way to directly operate on an object via an interface is to

  • Implement the methods of the interface with an object pointer as receiver
  • Instantiate the interface with the adress of the object
Some :?: library functions which return an interface in reality return a pointer to an implementation of the interface (see e.g. net.Listen)

Handling Errors

Defer, Panic, Recover: http://blog.golang.org/2010_08_01_archive.html ⇒ The convention in the Go libraries is that even when a package uses panic internally, its external API still returns explicit os.Error values.

os.Error is the same interface as fmt.Stringer, i.e. it has a method called String() wich returns a string. Thus an instance of os.Error can always be passed to the functions in fmt and log directly, without explicitely calling the String() method. E.g:

if err != nil {
    log.Panic(err)
}

FIXME See Exception Handling in C

Unsorted Things

Todo