====== 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