====== 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 [[golang>doc/install.html?h=weekly+release#releases|here]] ==== ARM5 (Sheevaplug) specific == * Current release version (release.r57.1 / 8295:95d2ce135523) does not work * Current weekly version (weekly.2011-06-02 / 8624:3418f22c39eb) works * ''export GOARM=5'' in ''~/.profile'' ! * export GOHOSTARCH=arm, export GOHOSTOS=linux, export GOARCH=arm, export GOOS=linux may be necessary too ==== 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 [[golang>pkg/fmt/]] ==== Command Line Arguments == Use the ''os.Args'' slice. [[golang>doc/go_tutorial.html|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 } [[golang>doc/go_spec.html#Variable_declarations|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. [[http://blog.golang.org/2011/01/go-slices-usage-and-internals.html|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) // 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. [[golang>pkg/net/#Listener.Listen|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. [[golang>pkg/os/#Error|os.Error]] is the same interface as [[golang>pkg/fmt/#Stringer|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 [[:becki:my:linux:exception_handling_in_c]] ===== Unsorted Things == * Since [[golang>doc/go_tutorial.html#tmp_94|strings are immutable values]] I guess only references are passed around if you pass the type ''string''. Thus it probably does not make much sense to use pointers to strings. * Seems to be convention that a function returns (among others) ''os.Error == nil'' when it succeded (tested) * ''if'' and ''switch'' accept an initialization statement, see [[golang>doc/effective_go.html#if]] * Number <=> String conversion is done with [[golang>pkg/strconv/]] * [[http://www.syntax-k.de/projekte/go-review|Interesting Go overview]] ===== Todo == * Where is variable argument list for functions? * Where is ''basename''? * Type Conversions look like function calls, see [[golang>doc/go_spec.html#Conversions]] * Check type assertion, eg. ''s, ok := v.(Stringer)'', see Tutorial