Welcome to a tour of the Go programming language.
The tour is divided into three sections. At the end of each section is a series of exercises for you to complete.
The tour is interactive. Click the Run button now (or type Shift-Enter) to compile and run the program on a remote server. your computer. The result is displayed below the code.
These example programs demonstrate different aspects of Go. The programs in the tour are meant to be starting points for your own experimentation.
Edit the program and run it again.
Whenever you're ready to move on, click the Next button or type the PageDown key.
This tour is also available as a stand-alone program that you can use without access to the internet.
The stand-alone tour is faster, as it builds and runs the code samples on your own machine. It also includes additional exercises not available in this sandboxed version.
To run the tour locally first
install Go (the latest stable release, release.r60),
then use
goinstall
to install
gotour:
goinstall go-tour.googlecode.com/hg/gotour
and run the resultant gotour executable.
Otherwise, click the "next" button or type PageDown to continue.
(You may return to these instructions at any time by clicking the "index" button.)
The tour is available in other languages:
(If you would like to translate the tour to another language, check
out the source from https://go-tour.googlecode.com/hg,
translate static/index.html, and then deploy it to App
Engine using the instructions in appengine/README.)
Click the "next" button or type PageDown to continue.
Every Go program is made up of packages.
Programs start running in package main.
This program is using the packages with import paths
"fmt" and "math".
By convention, the package name is the same as the last element of the import path.
This code groups the imports into a parenthesized, "factored" import statement. You can also write multiple import statements, like:
import "fmt" import "math"but it's common to use the factored form to eliminate clutter.
After importing a package, you can refer to the names it exports.
In Go, a name is exported if it begins with a capital letter.
Foo is an exported name, as is FOO.
The name foo is not exported.
Run the code. Then rename math.pi to math.Pi
and try it again.
A function can take zero or more arguments.
In this example, add takes two parameters of type int.
Notice that the type comes after the variable name.
(For more about why types look the way they do, see this blog post.)
When two or more consecutive named function parameters share a type, you can omit the type from all but the last.
In this example, we shortened
x int, y int
to
x, y int
A function can return any number of results.
This function returns two strings.
Functions take parameters; in Go results can be named and act like variables; these are called "result parameters."
If the result parameters are named, a return statement
without arguments returns the current values of the results.
The var statement declares a list of variables;
as in function argument lists, the type is last.
A var declaration can include initializers, one per variable.
If an initializer is present, the type can be omitted; the variable will take the type of the initializer.
Inside a function, the := short assignment statement
can be used in place of the short var declaration.
(Outside a function, every construct begins with a keyword and the
:= construct is not available.)
Constants are declared like variables, but with the const
keyword.
Constants can be string, boolean, or numeric values.
Numeric constants are high-precision values.
An untyped constant takes the type needed by its context.
Try printing needInt(Big) too.
Go has only one looping construct, the for loop.
The basic for loop looks as it does in C or Java,
except that the ( ) are gone (they are not even optional)
and the { } are required.
As in C or Java, you can leave the pre and post statements empty.
At that point you can drop the semicolons:
C's while is spelled for in Go.
If you omit the loop condition, it loops forever.
And with no clauses at all, the semicolons can be omitted, so an infinite loop is compactly expressed.
The if statement looks as it does in C or Java,
except that the ( ) are gone (they are not even optional)
and the { } are required.
(Sound familiar?)
Like for, the if statement can start with a
short statement to execute before the condition.
Variables declared by the statement are only in scope until the end of
the if.
(Try using v in the last return statement.)
Variables declared inside an if's short statement are also
available inside any of the else blocks.
Go's basic types are
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex64 complex128
A struct is a collection of fields.
(And a type declaration does what you'd expect.)
Struct fields are accessed using a dot.
Go has pointers, but no pointer arithmetic.
Struct fields can be accessed through a struct pointer. The indirection through the pointer is transparent.
A struct literal denotes a newly allocated struct value by listing the values of its fields.
You can list just a subset of fields by using the Name:
syntax. (And the order of named fields is irrelevant.)
The special prefix & constructs a pointer to a struct
literal.
new function
The expression new(T) allocates a zeroed T
value and returns a pointer to it.
var t *T = new(T)
or
t := new(T)
A map maps keys to values.
Maps must be created with make (not new)
before use; the nil map is empty and cannot be assigned
to.
Map literals are like struct literals, but the keys are required.
If the top-level type is just a type name, you can omit it from the elements of the literal.
A slice points to an array of values and also includes a length.
[]T is a slice with elements of type T.
Slices can be re-sliced, creating a new slice value that points to the same array.
The expression
s[lo:hi]
evaluates to a slice of the elements from lo through
hi-1, inclusive. Thus
s[lo:lo]
is empty and
s[lo:lo+1]
has one element.
Slices are created with the make function. It works by
allocating a zeroed array and returning a slice that refers to that
array:
a := make([]int, 5) // len(a)=5Slices have length and capacity. A slice's capacity is the maximum length the slice can grow within the underlying array.
To specify a capacity, pass a third argument to make:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5Slices can be grown by "re-slicing" (up to their capacity):
b = b[:cap(b)] // len(b)=5, cap(b)=5 b = b[1:] // len(b)=4, cap(b)=4
The zero value of a slice is nil.
A nil slice has a length and capacity of 0.
For more detail see the "Go Slices: usage and internals" article.
Functions are values too.
And functions are full closures.
The adder function returns a closure.
Each closure is bound to its own sum variable.
The range form of the for
loop iterates over a slice or map.
You can skip the key or value by assigning to _.
If you only want the index, drop the
“, value” entirely.
You probably knew what switch was going to look like.
A case body breaks automatically, unless it ends with a fallthrough statement.
Switch cases evaluate cases from top to bottom, stopping when a case succeeds.
(For example,
switch i {
case 0:
case f():
}
does not call f if i==0.)
Switch without a condition is the same as switch true.
As a simple way to play with functions and loops, implement the square root function using Newton's method.
In this case, Newton's method is to approximate Sqrt(x)
by picking a starting point z and then repeating:
To begin with, just repeat that calculation 10 times and see how close you get to the answer for various values (1, 2, 3, ...).
Next, change the loop condition to stop once the value has stopped changing (or only changes by a very small delta). See if that's more or fewer iterations. How close are you to the math.Sqrt?
Hint: to declare and initialize a floating point value, give it floating point syntax or use a conversion:
z := float64(1.0) z := 1.0
Implement WordCount. It should return a map of the
counts of each “word” in the string s.
The wc.Test function runs a test suite against the
provided function and prints success or failure.
You might find strings.Fields helpful.
Implement Pic. It should return a slice of length
dy, each element of which is a slice of dx
8-bit unsigned integers. When you run the program, it will display
your picture, interpreting the integers as grayscale (well, bluescale)
values.
The choice of image is up to you.
Interesting functions include x^y, (x+y)/2, and x*y.
(You need to use a loop to allocate each []uint8 inside
the [][]uint8.)
Let's have some fun with functions.
Implement a fibonacci function that returns a function
(a closure) that returns successive fibonacci numbers.
Let's explore Go's built-in support for complex numbers via the
complex64 and complex128 types.
For cube roots, Newton's method amounts to repeating:
Find the cube root of 2, just to make sure the algorithm works. There is a cmath.Pow function.
Go does not have classes. However, you can define methods on struct types.
The method receiver appears in its own argument list
between the func keyword and the method name.
In fact, you can define a method on any type you define in your package, not just structs.
You cannot define a method on a type from another package, or on a basic type.
Methods can be associated with a named type or a pointer to a named type.
We just saw two Abs methods. One on the
*Vertex pointer type and the other on the
MyFloat value type.
There are two reasons to use a pointer receiver. First, to avoid copying the value on each method call (more efficient if the value type is a large struct). Second, so that the method can modify the value that its receiver points to.
Try changing the declarations of the Abs and
Scale methods to use Vertex as the
receiver, instead of *Vertex.
The Scale method has no effect when v is a
Vertex. Scale mutates v. When
v is a value (non-pointer) type, the method sees a copy of
the Vertex and cannot mutate the original value.
Abs works either way. It only reads v.
It doesn't matter whether it is reading the original value (through a
pointer) or a copy of that value.
An interface type is defined by a set of methods.
A value of interface type can hold any value that implements those methods.
A type implements an interface by implementing the methods.
There is no explicit declaration of intent.
Implicit interfaces decouple implementation packages from the packages that define the interfaces: neither depends on the other.
It also encourages the definition of precise interfaces, because you don't have to find every implementation and tag it with the new interface name.
Package io defines Reader and Writer; you don't have to.
An error is anything that can describe itself:
package os
type Error interface {
String() string
}
Package http serves HTTP requests using any value
that implements http.Handler:
package http
type Handler interface {
ServeHTTP(w ResponseWriter,
r *Request)
}
In this example, the type MyHandler implements http.Handler.
Visit http://localhost:4000/ to see the greeting. Note: This example won't run through the web-based tour user interface. To try writing web servers you may want to Install Go.
Package image defines the Image
interface:
package image
type Image interface {
ColorModel() ColorModel
Bounds() Rectangle
At(x, y int) Color
}
(See the documentation for all the details.)
Color and ColorModel are interfaces too,
but we'll ignore that by using the predefined implementations
image.RGBAColor and image.RGBAColorModel.
Copy your Sqrt function from the earlier exercises and
modify it to return an os.Error value.
Sqrt should return a non-nil error value when given a
negative number, as it doesn't support complex numbers.
Create a new type
type ErrNegativeSqrt float64
and make it an os.Error by giving it a
func (e ErrNegativeSqrt) String() string
method such that ErrNegativeSqrt(-2).String() returns
"cannot Sqrt negative number: -2".
Note: a call to fmt.Print(e) inside the
String method will send the program into an infinite loop.
You can avoid this by converting e first:
fmt.Print(float64(e)). Why?
Change your Sqrt function to return an
ErrNegativeSqrt value when given a negative number.
Implement the following types and define ServeHTTP methods on them. Register them to handle specific paths in your web server.
type String string
type Struct struct {
Greeting string
Punct string
Who string
}
For example, you should be able to register handlers using:
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
Remember the picture generator you wrote earlier?
Let's write another one, but this time it will return
an implementation of image.Image instead of a slice of data.
Define your own Image type, implement
the necessary methods,
and call pic.ShowImage.
Bounds should return a image.Rectangle, like
image.Rect(0, 0, w, h).
ColorModel should return image.RGBAColorModel.
At should return a color;
the value v in the last picture generator corresponds to
image.RGBAColor{v, v, 255, 255} in this one.
A common pattern is an
io.Reader that wraps
another io.Reader, modifying the stream in some way.
For example, the
gzip.NewReader
function takes an io.Reader (a stream of gzipped data)
and returns a *gzip.Decompressor that also implements
io.Reader (a stream of the decompressed data).
Implement a rot13Reader that implements
io.Reader and reads from an io.Reader,
modifying the stream by applying the
ROT13
substitution cipher to all alphabetical characters.
The rot13Reader type is provided for you. Make it an
io.Reader by implementing its Read method.
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running
f(x, y, z)
The evaluation
of f, x, y, and z
happens in the current goroutine and the execution of f
happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory
must be synchronized. The sync package provides useful primitives,
although you won't need them much in Go as there are other primitives.
(See the next slide.)
Channels are a typed conduit through which you can send and receive values with the channel operator, <-.
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and
// assign value to v.
(The data flows in the direction of the "arrow".)
Like maps and slices, channels must be created before use:
ch := make(chan int)
By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.
Channels can be buffered. Provide the buffer length as the
second argument to make to initialize a buffered channel:
ch := make(chan int, 100)
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
Modify the example to overfill the buffer and see what happens.
A sender can close a channel to indicate that no more
values will be sent. Receivers can test whether a channel has been
closed by assigning a second parameter to the receive expression: after
v, ok := <-ch
ok is false if there are no more values to
receive and the channel is closed.
The loop for i := range c receives values from the
channel repeatedly until it is closed.
Note: Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.
Another note: Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming.
The select statement lets a goroutine wait on multiple
communication operations.
A select blocks until one of its cases can run, then it
executes that case. It chooses one at random if multiple are ready.
The default case in a select is run if no
other case is ready.
Use a default case to try a send or receive without
blocking:
select {
case i := <-c:
// use i
default:
// receiving from c would block
}
Note: This example won't run through the web-based tour user interface because the sandbox environment has no concept of time. You may want to install Go to see this example in action.
There can be many different binary trees with the same sequence of
values stored at the leaves.
For example, here are two binary trees storing the sequence
1, 1, 2, 3, 5, 8, 13.
A function to check whether two binary trees store the same sequence is quite complex in most languages. We'll use Go's concurrency and channels to write a simple solution.
This example uses the tree package, which defines the type:
type Tree struct {
Left *Tree
Value int
Right *Tree
}
1. Implement the Walk function.
2. Test the Walk function.
The function tree.New(k) constructs a randomly-structured
binary tree holding the values k, 2k, 3k, ...,
10k.
Create a new channel ch and kick off the walker:
go Walk(tree.New(1), ch)
Then read and print 10 values from the channel. It should be the numbers 1, 2, 3, ..., 10.
3. Implement the Same function using Walk
to determine whether t1 and t2 store the same values.
4. Test the Same function.
Same(tree.New(1), tree.New(1)) should return true, and
Same(tree.New(1), tree.New(2)) should return false.
In this exercise you'll use Go's concurrency features to parallelize a web crawler.
Modify the Crawl function to fetch URLs in parallel
without fetching the same URL twice.
You can get started by installing Go or downloading the Go App Engine SDK.
Once you have Go on your machine, the The Go Documentation is a great place to continue start. It contains references, tutorials, videos, and more.
If you need help with the standard library, see the package reference. For help with the language itself, you might be surprised to find the Language Spec is quite readable.
If you're interested in writing web applications, see the Wiki Codelab.
If you want to further explore Go's concurrency model, see the Share Memory by Communicating codewalk.
The First Class Functions in Go codewalk gives an interesting perspective on Go's function types.
The Go Blog has a large archive of informative Go articles.
Visit golang.org for more.