92

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.
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
  • ARM support such as 8-bit or 16-bit. D language still do not. –  Dec 27 '11 at 14:37
  • 1
    The library (http://golang.org/pkg/) is an excellent source to learn how go is used. Personally, I find that learning how data structures are implemented is helpful to learn the language. – tkokasih Oct 21 '13 at 11:19
  • Did you watch [this talk](http://www.youtube.com/watch?v=rKnDgT73v8s)? It shows a lot of cool stuff you can do (end of the talk) –  Nov 12 '09 at 06:01

24 Answers24

35

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)
}
Community
  • 1
  • 1
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
  • 17
    Looks like good old RAII (made explicit). – Konrad Rudolph Nov 14 '09 at 12:11
  • 4
    +1 since I read a lot about Go, but I still didn't see this (until you showed me)! – u0b34a0f6ae Nov 14 '09 at 19:36
  • Clever, although it would make more sense to me if defer statements where executed in FIFO order (top to bottom), but maybe that's just me... – Mike Spross Nov 15 '09 at 07:49
  • Cool. Reminds me of scrop guards from D http://www.digitalmars.com/d/2.0/exception-safe.html – hasen Nov 15 '09 at 12:45
  • 4
    @Mike: if you compare with blocks of "try:..finally:" LIFO nests in the same way. For resource open/close pairs etc, nesting like this is the only thing that makes sense (First open will close last). – u0b34a0f6ae Nov 18 '09 at 20:28
  • @kaizer: I guess it depends how you read the `defer` statements in your head :). Since it's in LIFO order, you have to read it "backwards" to see how it's releasing things (`defer CloseDatabase; defer CloseTable` means "Close the database AFTER you close the table"). If I didn't know any better, I would have written it as `defer CloseTable; defer CloseDatabase` because my first instinct would be to read it as "Close the table first, THEN close the database."). But backwards to me is correct to someone else ;) – Mike Spross Nov 18 '09 at 23:58
  • Like Kinopiko, I wonder what this is good for in real life? – raphink Dec 24 '09 at 10:21
  • No, @KonradRudolph, RAII is about objects termination, not just functions. "Defer" is more like try-catch. – OZ_ Aug 30 '14 at 12:21
  • @OZ_ RAII is only superficially about object termination. RAII is used to implement the same thing that you get from `try`–`finally` (*not* `catch`). They are not the same but they are used to support the same semantics. Put differently: where you’d use `defer` in Go you’d use RAII in languages that support it (mainly C++). – Konrad Rudolph Sep 02 '14 at 11:58
  • @KonradRudolph absolutely no. You don't understand what is RAII. Try to implement mutexes with try-catch (it will be funny). – OZ_ Sep 02 '14 at 13:11
  • @OZ_ I’m sorry but you have it the wrong way round. I do understand RAII (just search Stack Overflow for [my contributions on the subject](http://stackoverflow.com/tags/raii/topusers)), but I don’t know what you mean by implementing a mutex via try–catch, I never suggested doing that. You can trivially do it via try–finally, though. – Konrad Rudolph Sep 02 '14 at 15:46
  • @KonradRudolph then google little bit about mutexes and RAII :) You tried to prove that `defer` is the same thing as RAII, even despite of fact that `defer` works just in scope of function. So I tried to show you that with RAII you can do things which are much more hard to implement without RAII. Enough about it. If you still think RAII and `defer` is the same thing - we have nothing to talk about. – OZ_ Sep 02 '14 at 20:56
  • @OZ_ I never tried to prove that RAII is strictly the same as `defer`, just that they are used to solve the same problems. But if you want to have a mutex with `defer`, it’s easy enough (it’s a standard example of using a handle with try–finally, and trivially adaptable to `defer`): `m := mutex{}; defer m.unlock(); m.lock();` – I hope I got the Go syntax right: I never use it, but I use the same routinely in R (`defer` there is called `on.exit`). – Konrad Rudolph Sep 02 '14 at 21:32
25

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>
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
22

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 :)

j-g-faustus
  • 8,801
  • 4
  • 32
  • 42
19

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 (!)
Community
  • 1
  • 1
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
19

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.

Community
  • 1
  • 1
  • I'm not sure what was supposed to be wrong with the formatting; I've restored it. –  Nov 13 '09 at 12:30
  • 5
    The Go authors recommend to `gofmt` your code :-) – raphink Dec 24 '09 at 10:23
  • I can't compile it: $ ../go/src/cmd/6g/6g SO.go SO.go:34: undefined: json.StringToJson – raphink Dec 24 '09 at 10:27
  • @Raphink: the language has changed since I made this. –  Dec 24 '09 at 11:37
  • Yeah, do you know maybe what's the closest equivalent to the StringToJson? It used to set up a builder internally, now one has to provide their own with a predefined native structure? – macbirdie Jan 05 '10 at 15:03
18

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.

Rob Russell
  • 462
  • 3
  • 14
18

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.

u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
17

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");
}
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
16

When importing packages, you can redefine the name to anything you want:

package main

import f "fmt"

func main() {
    f.Printf("Hello World\n")
}
Isaiah
  • 4,201
  • 4
  • 27
  • 40
  • 3
    I've already made use of this: http://stackoverflow.com/questions/1726698/code-golf-sierpinskis-triangle/1727227#1727227 –  Nov 13 '09 at 16:54
14

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
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
  • 3
    The receive operator itself **is** now a blocking operation, as of Go 1.0.3 . The spec has been modified : http://golang.org/ref/spec#Receive_operator . Please try the blocking behavior (deadlock) here : http://play.golang.org/p/0yurtWW4Q3 – Deleplace Jan 27 '13 at 15:45
14

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;
}
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
13
/* 
 * 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))
}
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
  • 4
    I would suggest removing the name of the problem solving site as well as the id number. Maybe rephrase the question. As to not spoil the problem to someone stumbling over it. Or trying to cheat by searching for the problem on the net for that matter. – Mizipzor Nov 12 '09 at 10:02
  • 1
    For the record: this is the algorithm from http://www.algorithmist.com/index.php/Coin_Change It's the first Google result for "coin change". – György Andrasek Nov 12 '09 at 10:20
13

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.

j-g-faustus
  • 8,801
  • 4
  • 32
  • 42
12

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;
}
u0b34a0f6ae
  • 48,117
  • 14
  • 92
  • 101
  • +1. Also, you can pass channels through channels as well. – György Andrasek Nov 22 '09 at 20:42
  • 5
    But be careful not to break out of a for x := range chan {} loop, you'll leak the goroutine, and all the memory it references. – Jeff Allen Nov 12 '10 at 15:51
  • 3
    @JeffAllen how about `defer close(outch);` as the first statement of the goroutine? –  May 05 '13 at 15:48
  • 1
    Defer queues a statement for execution when the function returns, no matter which return point is taken. But if channel input is never closed, then the anonymous function in this example will never leave the for loop. – Jeff Allen May 08 '13 at 06:34
11
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)
}
mbarkhau
  • 8,190
  • 4
  • 30
  • 34
11

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.

György Andrasek
  • 8,187
  • 4
  • 48
  • 76
9

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.

Scott Wales
  • 11,336
  • 5
  • 33
  • 30
7

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()
}
7

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.

4

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.

Community
  • 1
  • 1
Scott Wales
  • 11,336
  • 5
  • 33
  • 30
  • 3
    Does it use the "flying dot", really? I don't dare edit, but that seems a bit unexpected and radical. – unwind Nov 12 '09 at 09:42
  • Yes, you need to compile with 6c (or 8c, etc). I don't think gcc handles unicode identifiers. – Scott Wales Nov 12 '09 at 09:43
  • 1
    I think AltGr+period types the same · but with unicode I'm not sure. Was very surprised to see that in source I read.. why not use something like ::? – u0b34a0f6ae Nov 14 '09 at 19:34
  • The character is MIDDLE DOT U+00B7. The parser may have been fudged so that it sees this as a character in order to make a valid c identifier, which I believe would preclude ::. – Scott Wales Nov 14 '09 at 20:59
  • 4
    The '·' is just a temporary hack, rob was even surprised it was still there, he said it was going to be replaced with something less idiosyncratic. – uriel Nov 14 '09 at 23:17
  • What language is that second code fragment written in? It's neither go nor C. – finnw Nov 16 '09 at 23:27
  • The one with include "runtime.h" is c, I missed the hash. int32, String etc. are defined in the runtime header. – Scott Wales Nov 17 '09 at 00:01
  • ALT + SHIFT + 9(not keypad) = '·' on OS X Mav – Brenden Jan 09 '14 at 01:20
4

Here is a go example using the sqlite3 package.

http://github.com/bikal/gosqlite-example

Bikal Lem
  • 2,403
  • 18
  • 19
3
const ever = true

for ever {
    // infinite loop
}
György Andrasek
  • 8,187
  • 4
  • 48
  • 76
3

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()
}
Jeff Allen
  • 1,391
  • 13
  • 19
2

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.