Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
becki:linux:golang [2011-02-16 13:52] becki |
becki:linux:golang [2018-02-26 11:24] (aktuell) becki |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== Go Programming Language Tips ====== | + | ====== Go Programming Language Tips == |
===== Setup == | ===== Setup == | ||
Zeile 14: | Zeile 14: | ||
#!/bin/sh | #!/bin/sh | ||
export PATH="$PATH:/usr/local/go/bin" | export PATH="$PATH:/usr/local/go/bin" | ||
+ | export GOROOT=/usr/local/go | ||
</code> | </code> | ||
Go Syntax Highlighting for your editor at http://go-lang.cat-v.org/text-editors/ | 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'': | ||
+ | |||
+ | <code bash> | ||
+ | export GOROOT=$(pwd) | ||
+ | export GOHOSTARCH=386 | ||
+ | export GOHOSTOS=linux | ||
+ | export GOARCH=arm | ||
+ | export GOOS=linux | ||
+ | export GOARM=5 | ||
+ | </code> | ||
+ | |||
===== Hello World == | ===== Hello World == | ||
Zeile 25: | Zeile 51: | ||
func main() { | func main() { | ||
- | fmt.Printf("Hallo Süße!\n") | + | fmt.Printf("Hallo Süße!\n") |
} | } | ||
</code> | </code> | ||
- | Build & run: ''8g hello.go && 8l -o hello hello.8 && ./hello'' | + | 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/]] | 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 == | ===== Variable Declaration == | ||
- | <code go> | + | <code go> |
package main | package main | ||
import "fmt" | import "fmt" | ||
func main() { | func main() { | ||
var i,j int // 2 ints, autoinitialized to zero value | var i,j int // 2 ints, autoinitialized to zero value | ||
- | fmt.Printf("%d %d\n", i, j) // 0 0 | + | fmt.Printf("%d %d\n", i, j) // 0 0 |
var k,l,m,n= true, 0, 2.6, "Hello" // missing types default to: | 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("%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.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 | fmt.Println(k,l,m,n) // -> true 0 2.6 Hello | ||
o,p:= false, "World" // short form: no type but initializers: | o,p:= false, "World" // short form: no type but initializers: | ||
- | fmt.Printf("%T %T\n", o,p) // -> bool string | + | fmt.Printf("%T %T\n", o, p) // -> bool string |
fmt.Println(o,p) // -> false World | fmt.Println(o,p) // -> false World | ||
} | } | ||
Zeile 58: | Zeile 101: | ||
<code go> | <code go> | ||
+ | a := [...]int{0, 1, 2, 3} // an array created literally | ||
+ | a := [4]int // create a zeroed array (?) | ||
+ | </code> | ||
+ | |||
+ | <code go> | ||
package main | package main | ||
import "fmt" | import "fmt" | ||
func main() { | func main() { | ||
- | //var ia= [...]int{47,11} // Create an array literal | + | //var ia= [...]int{47, 11} // Create an array literal |
ia:= [...]int{47,11} // Create an array literal - short form | ia:= [...]int{47,11} // Create an array literal - short form | ||
Zeile 88: | Zeile 136: | ||
</code> | </code> | ||
- | * The length of the array is part of its type and cannot grow | + | <note tip> |
- | * Arrays are real types, are copied by value, pointers to array are possible | + | |
+ | * 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) | ||
+ | |||
+ | </note> | ||
===== Slices == | ===== Slices == | ||
<code go> | <code go> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | <code go> | ||
package main | package main | ||
import "fmt" | import "fmt" | ||
func main() { | func main() { | ||
- | a:= [...]int{0,1,2,3} // an array to play with | + | a:= [...]int{0, 1, 2, 3} // an array to play with |
sa:= a[:] // Create slice from whole array | sa:= a[:] // Create slice from whole array | ||
- | sb:= a[:2] // Create slice from last part | + | sb:= a[:2] // Create slice from first part |
- | sc:= 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(sa, len(sa), cap(sa)) // -> [0 1 2 3] 4 4 | ||
fmt.Println(sb, len(sb), cap(sb)) // -> [0 1] 2 4(!) | fmt.Println(sb, len(sb), cap(sb)) // -> [0 1] 2 4(!) | ||
Zeile 127: | Zeile 188: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | <note tip> | ||
+ | * 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(?)) | ||
+ | |||
+ | </note> | ||
+ | <note important>Appending to a Slice results in a new slice. The new slice may point to a different array than the original slice.</note> | ||
[[http://blog.golang.org/2011/01/go-slices-usage-and-internals.html|more]] | [[http://blog.golang.org/2011/01/go-slices-usage-and-internals.html|more]] | ||
+ | ===== Objects == | ||
+ | ==== Copying Objects == | ||
+ | |||
+ | <code go> | ||
+ | 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} | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note tip>Objects are copied **by value**</note> | ||
+ | |||
+ | ==== Methods == | ||
+ | |||
+ | <code go> | ||
+ | /** 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} | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note tip> | ||
+ | |||
+ | * 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. | ||
+ | |||
+ | </note> | ||
+ | |||
+ | ==== Interfaces == | ||
+ | |||
+ | <code go> | ||
+ | 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} | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note tip> | ||
+ | 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 | ||
+ | |||
+ | </note> | ||
+ | <note important>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]])</note> | ||
+ | |||
+ | ===== 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: | ||
+ | |||
+ | <code go> | ||
+ | if err != nil { | ||
+ | log.Panic(err) | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | 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 | ||