There's not a lot of Go code to learn the language from, and I'm sure I'm not the only one experimenting with it. So, if you found out something interesting about开发者_运维百科 the language, please post an example here.
I'm also looking for
- idiomatic ways to do things in Go,
- C/C++ style of thinking "ported" to Go,
- common pitfalls about the syntax,
- anything interesting, really.
Defer statements
A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns.
DeferStmt = "defer" Expression .
The expression must be a function or method call. Each time the "defer" statement executes, the parameters to the function call are evaluated and saved anew but the function is not invoked. Deferred function calls are executed in LIFO order immediately before the surrounding function returns, but after the return values, if any, have been evaluated.
lock(l);
defer unlock(l); // unlocking happens before surrounding function returns
// prints 3 2 1 0 before surrounding function returns
for i := 0; i <= 3; i++ {
defer fmt.Print(i);
}
Update:
defer
is now also the idiomatic way to handle panic
in an exception-like manner:
package main
import "fmt"
func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i+1)
}
Go object files actually include a cleartext header:
jurily@jurily ~/workspace/go/euler31 $ 6g euler31.go
jurily@jurily ~/workspace/go/euler31 $ cat euler31.6
amd64
exports automatically generated from
euler31.go in package "main"
import
$$ // exports
package main
var main.coin [9]int
func main.howmany (amount int, max int) (? int)
func main.main ()
var main.initdone· uint8
func main.init ()
$$ // local types
type main.dsigddd_1·1 struct { ? int }
$$
!
<binary segment>
I have seen a couple of people complaining about the for-loop, along the lines of "why should we have to say i = 0; i < len; i++
in this day and age?".
I disagree, I like the for construct. You can use the long version if you wish, but the idiomatic Go is
var a = []int{1, 2, 3}
for i, v := range a {
fmt.Println(i, v)
}
The for .. range
construct loops over all the elements and supplies two values - the index i
and the value v
.
range
also works on maps and channels.
Still, if you dislike for
in any form, you can define each
, map
etc. in a few lines:
type IntArr []int
// 'each' takes a function argument.
// The function must accept two ints, the index and value,
// and will be called on each element in turn.
func (a IntArr) each(fn func(index, value int)) {
for i, v := range a {
fn(i, v)
}
}
func main() {
var a = IntArr([]int{2, 0, 0, 9}) // create int slice and cast to IntArr
var fnPrint = func(i, v int) {
fmt.Println(i, ":", v)
} // create a function
a.each(fnPrint) // call on each element
}
prints
0 : 2
1 : 0
2 : 0
3 : 9
I'm starting to like Go a lot :)
Go and get your stackoverflow reputation
This is a translation of this answer.
package main
import (
"json"
"fmt"
"http"
"os"
"strings"
)
func die(message string) {
fmt.Printf("%s.\n", message);
os.Exit(1);
}
func main() {
kinopiko_flair := "https://stackoverflow.com/users/flair/181548.json"
response, _, err := http.Get(kinopiko_flair)
if err != nil {
die(fmt.Sprintf("Error getting %s", kinopiko_flair))
}
var nr int
const buf_size = 0x1000
buf := make([]byte, buf_size)
nr, err = response.Body.Read(buf)
if err != nil && error != os.EOF {
die(fmt.Sprintf("Error reading response: %s", err.String()))
}
if nr >= buf_size { die ("Buffer overrun") }
response.Body.Close()
json_text := strings.Split(string(buf), "\000", 2)
parsed, ok, errtok := json.StringToJson(json_text[0])
if ! ok {
die(fmt.Sprintf("Error parsing JSON %s at %s", json_text, errtok))
}
fmt.Printf("Your stackoverflow.com reputation is %s\n", parsed.Get ("reputation"))
}
Thanks to Scott Wales for help with .Read ().
This looks fairly clunky still, with the two strings and two buffers, so if any Go experts have advice, let me know.
Here's a nice example of iota from Kinopiko's post:
type ByteSize float64
const (
_ = iota; // ignore first value by assigning to blank identifier
KB ByteSize = 1<<(10*iota)
MB
GB
TB
PB
YB
)
// This implicitly repeats to fill in all the values (!)
You can swap variables by parallel assignment:
x, y = y, x
// or in an array
a[j], a[i] = a[i], a[j]
simple but effective.
Here's an idiom from the Effective Go page
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
The switch statement switches on true when no expression is given. So this is equivalent to
if '0' <= c && c <= '9' {
return c - '0'
} else if 'a' <= c && c <= 'f' {
return c - 'a' + 10
} else if 'A' <= c && c <= 'F' {
return c - 'A' + 10
}
return 0
At the moment, the switch version looks a little cleaner to me.
Type switches:
switch i := x.(type) {
case nil:
printString("x is nil");
case int:
printInt(i); // i is an int
case float:
printFloat(i); // i is a float
case func(int) float:
printFunction(i); // i is a function
case bool, string:
printString("type is bool or string"); // i is an interface{}
default:
printString("don't know the type");
}
When importing packages, you can redefine the name to anything you want:
package main
import f "fmt"
func main() {
f.Printf("Hello World\n")
}
Named result parameters
The return or result "parameters" of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.
The names are not mandatory but they can make code shorter and clearer: they're documentation. If we name the results of nextInt it becomes obvious which returned int is which.
func nextInt(b []byte, pos int) (value, nextPos int) {
Because named results are initialized and tied to an unadorned return, they can simplify as well as clarify. Here's a version of io.ReadFull that uses them well:
func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
for len(buf) > 0 && err == nil {
var nr int;
nr, err = r.Read(buf);
n += nr;
buf = buf[nr:len(buf)];
}
return;
}
From James Antill's answer:
foo := <-ch // This blocks.
foo, ok := <-ch // This returns immediately.
Also, a potential pitfall: the subtle difference between the receive and send operators:
a <- ch // sends ch to channel a
<-ch // reads from channel ch
/*
* How many different ways can £2 be made using any number of coins?
* Now with 100% less semicolons!
*/
package main
import "fmt"
/* This line took me over 10 minutes to figure out.
* "[...]" means "figure out the size yourself"
* If you only specify "[]", it will try to create a slice, which is a reference to an existing array.
* Also, ":=" doesn't work here.
*/
var coin = [...]int{0, 1, 2, 5, 10, 20, 50, 100, 200}
func howmany(amount int, max int) int {
if amount == 0 { return 1 }
if amount < 0 { return 0 }
if max <= 0 && amount >= 1 { return 0 }
// recursion works as expected
return howmany(amount, max-1) + howmany(amount-coin[max], max)
}
func main() {
fmt.Println(howmany(200, len(coin)-1))
}
I like that you can redefine types, including primitives like int, as many times as you like and attach different methods. Like defining a RomanNumeral type:
package main
import (
"fmt"
"strings"
)
var numText = "zero one two three four five six seven eight nine ten"
var numRoman = "- I II III IV V VI VII IX X"
var aText = strings.Split(numText, " ")
var aRoman = strings.Split(numRoman, " ")
type TextNumber int
type RomanNumber int
func (n TextNumber) String() string {
return aText[n]
}
func (n RomanNumber) String() string {
return aRoman[n]
}
func main() {
var i = 5
fmt.Println("Number: ", i, TextNumber(i), RomanNumber(i))
}
Which prints out
Number: 5 five V
The RomanNumber()
call is essentially a cast, it redefines the int type as a more specific type of int. And Println()
calls String()
behind the scenes.
Returning a channel
This is a true idiom that is quite important: how to feed data into a channel and close it afterwards. With this you can make simple iterators (since range will accept a channel) or filters.
// return a channel that doubles the values in the input channel
func DoublingIterator(input chan int) chan int {
outch := make(chan int);
// start a goroutine to feed the channel (asynchronously)
go func() {
for x := range input {
outch <- 2*x;
}
// close the channel we created and control
close(outch);
}();
return outch;
}
Timeout for channel reads:
ticker := time.NewTicker(ns);
select {
case v := <- chan_target:
do_something_with_v;
case <- ticker.C:
handle_timeout;
}
Stolen from Davies Liu.
for {
v := <-ch
if closed(ch) {
break
}
fmt.Println(v)
}
Since range automatically checks for a closed channel, we can shorten to this:
for v := range ch {
fmt.Println(v)
}
There is a make system set up that you can use in $GOROOT/src
Set up your makefile with
TARG=foobar # Name of package to compile
GOFILES=foo.go bar.go # Go sources
CGOFILES=bang.cgo # Sources to run cgo on
OFILES=a_c_file.$O # Sources compiled with $Oc
# $O is the arch number (6 for x86_64)
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
You can then use the automated testing tools by running make test, or add the package and shared objects from cgo to your $GOROOT with make install.
Another interesting thing in Go is that godoc
. You can run it as a web server on your computer using
godoc -http=:8080
where 8080 is the port number, and the entire website at golang.org is then available at localhost:8080
.
This is an implementation of a stack. It illustrates adding methods onto a type.
I wanted to make the stack part of it into a slice and use the slice's properties, but although I got that to work without the type
, I couldn't see the syntax for defining a slice with a type
.
package main
import "fmt"
import "os"
const stack_max = 100
type Stack2 struct {
stack [stack_max]string
size int
}
func (s *Stack2) push(pushed_string string) {
n := s.size
if n >= stack_max-1 {
fmt.Print("Oh noes\n")
os.Exit(1)
}
s.size++
s.stack[n] = pushed_string
}
func (s *Stack2) pop() string {
n := s.size
if n == 0 {
fmt.Print("Underflow\n")
os.Exit(1)
}
top := s.stack[n-1]
s.size--
return top
}
func (s *Stack2) print_all() {
n := s.size
fmt.Printf("Stack size is %d\n", n)
for i := 0; i < n; i++ {
fmt.Printf("%d:\t%s\n", i, s.stack[i])
}
}
func main() {
stack := new(Stack2)
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()
}
Calling c code from go
It's possible to access the lower level of go by using the c runtime.
C functions are in the form
void package·function(...)
(note the dot seperator is a unicode character) where the arguments may be basic go types, slices, strings etc. To return a value call
FLUSH(&ret)
(you can return more than one value)
For instance, to create a function
package foo
bar( a int32, b string )(c float32 ){
c = 1.3 + float32(a - int32(len(b))
}
in C you use
#include "runtime.h"
void foo·bar(int32 a, String b, float32 c){
c = 1.3 + a - b.len;
FLUSH(&c);
}
Note that you still should declare the function in a go file, and that you'll have to take care of memory yourself. I'm not sure if it's possible to call external libraries using this, it may be better to use cgo.
Look at $GOROOT/src/pkg/runtime for examples used in the runtime.
See also this answer for linking c++ code with go.
Here is a go example using the sqlite3 package.
http://github.com/bikal/gosqlite-example
A stack based on the other answer, but using slice appending to have no size limit.
package main
import "fmt"
import "os"
type Stack2 struct {
// initial storage space for the stack
stack [10]string
cur []string
}
func (s *Stack2) push(pushed_string string) {
s.cur = append(s.cur, pushed_string)
}
func (s *Stack2) pop() (popped string) {
if len(s.cur) == 0 {
fmt.Print("Underflow\n")
os.Exit(1)
}
popped = s.cur[len(s.cur)-1]
s.cur = s.cur[0 : len(s.cur)-1]
return
}
func (s *Stack2) print_all() {
fmt.Printf("Stack size is %d\n", len(s.cur))
for i, s := range s.cur {
fmt.Printf("%d:\t%s\n", i, s)
}
}
func NewStack() (stack *Stack2) {
stack = new(Stack2)
// init the slice to an empty slice of the underlying storage
stack.cur = stack.stack[0:0]
return
}
func main() {
stack := NewStack()
stack.print_all()
stack.push("boo")
stack.print_all()
popped := stack.pop()
fmt.Printf("Stack top is %s\n", popped)
stack.print_all()
stack.push("moo")
stack.push("zoo")
stack.print_all()
popped2 := stack.pop()
fmt.Printf("Stack top is %s\n", popped2)
stack.print_all()
}
const ever = true
for ever {
// infinite loop
}
There are a lot of small programs in test
in the main directory. Examples:
peano.go
prints factorials.hilbert.go
has some matrix multiplication.iota.go
has examples of the weird iota thing.
精彩评论