This text is intended to help Java programmers
come up to speed quickly with Go.

It starts with an example highlighting features
easily recognized by all Java programmers,
then gives a fairly detailed description of Go’s building blocks,
and ends with an example illustrating constructs
that have no immediate counterpart in Java.

Hello stack (example)

To whet your appetite, we start with a small but complete and idiomatic example
corresponding to this Stack.java program.

The test package collection_test resides in the same directory
as the collection package.
The first import declaration indicates that we will use the package from the current
directory (".") and that we will refer to it by
the name collection within this file.
The second import declaration contains the path ("fmt") to a
standard package; since no name is given, the actual package name,
fmt, will be used by default.

Conceptual differences

Go does not have classes with constructors.
Instead of instance methods, a class inheritance hierarchy,
and dynamic method lookup, Go provides
structs and
interfaces.
Interfaces are also used where Java uses generics.

Go offers pointers to values of all types, not just objects and arrays.
For any type T, there is a corresponding pointer type
*T, denoting pointers
to values of type T.

Go allows methods on any type; no boxing is required.
The method receiver,
which corresponds to this in Java,
can be a direct value or a pointer.

Arrays in Go are values. When an array is used as a
function parameter, the function receives a copy of the array,
not a pointer to it. However, in practice functions often use
slices for parameters;
slices are references to underlying arrays.

Strings are provided by the language; a string behaves like a
slice of bytes, but is immutable.

Hash tables are provided by the language. They are called maps.

Separate threads of execution, goroutines,
and communication channels between them, channels,
are provided by the language.

Certain types (maps, slices, and channels) are passed by reference,
not by value. That is, passing a map to a function does not copy the map;
if the function changes the map, the change will be seen by the caller.
In Java terms, one can think of this as being a reference to the map.

Go provides two access levels, analogous to Java’s public and
package-private. Top-level declarations are public if their names
start with an upper-case letter, otherwise they are package-private.

Instead of exceptions, Go uses values of type
error to signify events such as end-of-file,
and run-time panics for run-time errors
such as attempting to index an array out of bounds.

Go does not support implicit type conversion. Operations that mix
different types require an explicit conversion.

Go does not support function overloading.
Functions and methods in the same scope must have unique names.

Go uses nil for invalid pointers, where Java uses
null.

Syntax

Declarations

The declaration syntax is reversed compared to Java.
You write the name followed by the type.
Type declarations may be read easily from left to right.

Go

Approximate Java equivalent

var v1 int

int v1 = 0;

var v2 *int

Integer v2 = null;

var v3 string

String v3 = "";

var v4 [10]int

int[] v4 = new int[10]; // v4 is a value in Go.

var v5 []int

int[] v5 = null;

var v6 *struct { a int }

C v6 = null; // Given: class C { int a; }

var v7 map[string]int

HashMap<String,Integer> v7 = null;

var v8 func(a int) int

F v8 = null; // interface F { int f(int a); }

Declarations generally take the form of a keyword followed by the name
of the object being declared. The keyword is one of const,
type, var, or func.
You can also use a keyword followed by a series of declarations in
parentheses.

var (
n int
x float64
)

When declaring a function, you must either provide a name for each parameter
or not provide a name for any parameter; you can’t omit some names
and provide others. You may group several names with the same type:

func f(i, j, k int, s, t string)

A variable may be initialized when it is declared. When this is done,
specifying the type of the variable is permitted but not required.
When the type is not specified, it defaults to the type of
the initialization expression.

var v9 = *v2

If a variable is not initialized explicitly, the type must be specified.
In that case it will be implicitly initialized to the type’s
zero value
(0, nil, "", etc.).
There are no uninitialized variables in Go.

Short declarations

Within a function, a short declaration syntax is available
with := .

v10 := v1

This is equivalent to

var v10 = v1

Function types

In Go, functions are first-class citizens.
Go’s function type denotes the set of all functions
with the same parameter and result types.

Multiple assignment

Go permits multiple assignments.
The expressions on the right are evaluated
before assigning to any of the operands on the left.

i, j = j, i // Swap i and j.

Functions may have multiple return values, indicated by a list in
parentheses. The returned values can be stored by assignment
to a list of variables.

func f() (i int, pj *int) { ... }
v1, v2 = f()

The blank identifier

The blank identifier, represented by the underscore character,
provides a way to ignore values returned by a multi-valued expression:

v1, _ = f() // Ignore second value returned by f().

Semicolons and formatting

Instead of worrying about semicolons and formatting, you may use
the gofmt program to produce a single standard Go style.
While this style may initially seem odd, it is as good as any other style,
and familiarity will lead to comfort.

Go code uses very few semicolons in practice. Technically, all Go
statements are terminated by a semicolon. However, Go
implicitly inserts a semicolon at the end of a non-blank line
unless the line is clearly incomplete.
A consequence of this is that in some cases Go does not permit a line break.
For example, you may not write

func g()
{ // INVALID; "{" should be on previous line.
}

A semicolon will be inserted after g()
causing it to be a function declaration rather than a function definition.
Similarly, you may not write

A semicolon will be inserted after the } preceding
the else, causing a syntax error.

Conditional statements

Go does not use parentheses around the condition of
an if statement,
or the expressions of a for statement,
or the value of a switch statement.
On the other hand, it does require curly braces around
the body of an if or for statement.

Furthermore, if and switch accept
an optional initialization statement, which is commonly used
to set up a local variable.

if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}

For statements

Go does not have a while statement
nor does it have a do-while statement.
The for statement may be used with a single condition,
which makes it equivalent to a while statement.
Omitting the condition entirely produces an endless loop.

A for statement may contain a range clause
for iterating over strings, arrays, slices, maps, or channels.
Instead of writing

for i := 0; i < len(a); i++ { ... }

to loop over the elements of a, we could also write

for i, v := range a { ... }

This assigns i to the index and v
to the value of the successive elements of an array, slice, or string.
For strings, i is an index to a byte and
v is a Unicode code point of type rune
(rune is an alias for int32).
Iterations over maps produce key-value pairs,
while channels produce only one iteration value.

Break and continue

Like Java, Go permits break and continue
to specify a label, but the label must refer to a for,
switch, or select statement.

Switch statements

In a switch statement, case labels
do not fall through by default,
but you can make them fall through by ending a case
with a fallthrough statement.

The values in a case can be any type that supports
the equality comparison operator, such as strings or pointers.
A missing switch expression is equivalent to
the expression true.

switch {
case n < 0:
f1()
case n == 0:
f2()
default:
f3()
}

++ and -- statements

The ++ and -- may only be used
as postfix operators and only in statements, not in expressions.
For example, you cannot write n = i++.

The defer statement

A defer statement invokes a function whose execution is
deferred to the moment the surrounding function returns.
The deferred function will be executed regardless of which path
the surronding function takes to return.
The parameters of the deferred function, however, are computed and saved
for future use already when the defer statement executes.

Constants

In Go constants may be untyped.
This applies to numeric literals, expressions using only untyped constants,
and const declarations where no type is given and
the initializer expression is untyped.
A value derived from an untyped constant becomes typed when it
is used within a context that requires a typed value.
This permits constants to be used relatively freely even though
Go has no implicit type conversion.

The language does not impose any limits on the size of an untyped
numeric constant. A limit is only applied when a constant is used
where a type is required.

const huge = 1 << 100
var n int = huge >> 98

If the type is absent in a variable declaration and the corresponding
expression evaluates to an untyped numeric constant,
the constant is converted to type rune, int,
float64, or complex128 respectively,
depending on whether the value is a character, integer, floating-point, or
complex constant.

Go does not have enumerated types.
Instead, you can use the special name iota in a single
const declaration to get a series of increasing value.
When an initialization expression is omitted for a const,
it reuses the preceding expression.

Structs

A struct corresponds to a class in Java, but the members of a struct
cannot be methods, only variables.
A pointer to a struct is similar to a reference variable in Java.
As opposed to Java classes, structs may also be defined as direct values.
In both cases you use . to access the members of a struct.

Pointers

If you have an int or a struct or an array,
assignment copies the contents of the object.
To achieve the effect of Java reference variables, Go uses pointers.
For any type T, there is a corresponding
pointer type *T,
denoting pointers to values of type T.

To allocate storage for a pointer variable,
use the built-in function new,
which takes a type and returns a pointer to the allocated storage.
The allocated space will be zero-initialized for the type.
For example, new(int) allocates storage
for a new int,
initializes it with the value 0,
and returns its address, which has type *int.

The Java code T p = new T(),
where T is a class with two instance variables
a and b of type int,
corresponds to

type T struct { a, b int }
var p *T = new(T)

or the more idiomatic

p := new(T)

The declaration var v T,
which declares a variable that holds a value of type T,
has no equivalent in Java.
Values can also be created and initialized using a composite literal.
For example:

v := T{1, 2}

is equivalent to

var v T
v.a = 1
v.b = 2

For an operand x of type T,
the address operator&x
gives the address of x, a value of type *T.
For example:

p := &T{1, 2} // p has type *T

For an operand x of pointer type,
the pointer indirection*x
denotes the value pointed to by x.
Pointer indirections are rarely used;
Go, just like Java, can automatically take the address of a variable:

p := new(T)
p.a = 1 // equivalent to (*p).a = 1

Slices

A slice is conceptually a struct with three fields:
a pointer into an array, a length, and a capacity.
Slices support the [] operator
to access elements of the underlying array.
The built-in len function returns the length of the slice.
The built-in cap function returns the capacity.

Given an array, or another slice, a new slice is created via
a[i:j]. This creates a new slice which refers to a,
starts at index i, and ends before index j.
It has length j - i.
If i is omitted, the slice starts at 0.
If j is omitted, the slice ends at len(a).
The new slice refers to the same array to which a refers.
That is, changes made to the elements using the new slice
may be seen using a.
The capacity of the new slice is simply the capacity of a
minus i.
The capacity of an array is the length of the array.

var s []int
var a [10]int
s = a[:] // short for s = a[0:len(a)]

If you create a value of type [100]byte
(an array of 100 bytes, perhaps a buffer)
and you want to pass it to a function without copying it,
declare the function parameter to have type []byte,
and pass a slice of the array.
Slices may also be created using the make function
as described below.

Slices combined with the built-in function append offer
much the same functionality as Java’s ArrayList.

The slice syntax may also be used with a string. It returns a new string
whose value is a substring of the original string.

Making values

Map and channel values must be allocated using the built-in function
make. For example, calling

make(map[string]int)

returns a newly allocated value of type map[string]int.
As opposed to new, make returns
the actual object, not an address. This is consistent with the fact
that maps and channels are reference types.

For maps, make takes a capacity hint as an optional second argument.
For channels, there is an optional second argument that sets the
buffering capacity of the channel; the default is 0 (unbuffered).

The make function may also be used to allocate a slice.
In this case it allocates memory for the underlying array and returns
a slice referring to it.
There is one required argument, which is the number of elements in the slice.
A second optional argument is the capacity of the slice.

m := make([]int, 10, 20) // Same as new([20]int)[:10]

Methods and interfaces

Methods

A method looks like an ordinary function definition,
except that it has a receiver.
The receiver is similar to the this reference
in a Java instance method.

Interfaces

A Go interface is similar to a Java interface,
but any type that provides the methods named in a Go interface
may be treated as an implementation of that interface.
No explicit declaration is required.

Given this interface:

type MyInterface interface {
Get() int
Set(i int)
}

Since MyType already has a Get method,
we can make MyType satisfy the interface by adding

func (p *MyType) Set(i int) {
p.i = i
}

Now any function which takes MyInterface as a parameter
will accept a variable of type *MyType.

The Set method is inherited from MyType,
because methods associated with the anonymous field are promoted
to become methods of the enclosing type.
In this case, because MySubType has an anonymous field
of type MyType, the methods of MyType also
become methods of MySubType.
The Get method was overridden,
and the Set method was inherited.

This is not precisely the same as a subclass in Java.
When a method of an anonymous field is called, its receiver is the field,
not the surrounding struct. In other words, methods on anonymous fields
are not dynamically dispatched. When you want the equivalent of Java’s
dynamic method lookup, use an interface.

Type assertions

A variable that has an interface type may be converted to have a
different interface type using a type assertion.
This is implemented dynamically at run time. Unlike Java, there does not
need to be any declared relationship between the two interfaces.

StringStack specializes the generic Stack
from the Hello stack example
so that it operates on string elements only ‒
just like Stack<String> in Java.
Notice that the Size method is inherited
from Stack.

Errors

Where Java typically uses exceptions, Go has two different mechanisms.
Most functions return errors; only truly unrecovorable conditions,
such as an out-of-range index, produce run-time exceptions.

The error interface requires only an Error method,
but specific error implementations often have additional methods,
allowing callers to inspect the details of the error.

Panic and recover

A panic is a run-time error
that unwinds the stack of the goroutine,
running any deferred functions along the way,
and then stops the program.
Panics are similar to Java exceptions,
but are only intended for run-time errors,
such as following a nil pointer or
attempting to index an array out of bounds.
To signify events such as end-of-file, Go programs use the built-in
error type as described above.

The built-in function recover can be used to regain
control of a panicking goroutine and resume normal execution.
A call to recover stops the unwinding and returns
the argument passed to panic.
Because the only code that runs while unwinding is inside deferred functions,
recover is only useful inside deferred functions.
If the goroutine is not panicking,
recover returns nil.

Goroutines and channels

Sushi conveyor belt

Goroutines

Go permits starting a new thread of execution, a goroutine,
using the go statement.
It runs a function in a different, newly created, goroutine.
All goroutines in a single program share the same address space.

Goroutines are lightweight,
costing little more than the allocation of stack space.
The stacks start small and grow by allocating and freeing
heap storage as required.
Internally goroutines act like coroutines that are multiplexed
among multiple operating system threads.
You do not have to worry about these details.

go list.Sort() // Run list.Sort in parallel; don’t wait for it.

Go has function literals, which can act as closures
and are powerful when coupled with the go statement.

The variables text and delay
are shared between the surrounding function and the function literal;
they survive as long as they are accessible.

Channels

A channel provides a mechanism for two goroutines to synchronize
execution and communicate by passing a value of a specified
element type.
The <- operator specifies the channel direction,
send or receive. If no direction is given, the channel is bi-directional.

chan Sushi // can be used to send and receive values of type Sushi
chan<- float64 // can only be used to send float64s
<-chan int // can only be used to receive ints

To send a value on a channel,
use <- as a binary operator.
To receive a value on a channel, use it as a unary operator.

ic <- 3 // Send 3 on the channel.
work := <-wc // Receive a pointer to Work from the channel.

If the channel is unbuffered,
the sender blocks until the receiver has received the value.
If the channel has a buffer,
the sender blocks only until the value has been copied to the buffer;
if the buffer is full,
this means waiting until some receiver has retrieved a value.
Receivers block until there is data to receive.

The close function records that no more values
will be sent on a channel. After calling close,
and after any previously sent values have been received,
receive operations will return a zero value without blocking.
A multi-valued receive operation additionally returns
an indication of whether the channel is closed.

wait := Publish("important news", 2 * time.Minute)
// Do some more work.
<-wait // blocks until the text has been published

Select statement

The select statement is the final tool in Go’s concurrency toolkit.
It chooses which of a set of possible communications will proceed.
If any of the communications can proceed, one of them is randomly
chosen and the corresponding statements are executed.
Otherwise, if there is no default case,
the statement blocks until one of the communications can complete.

Here is a toy example showing how the select statement can
be used to implement a random number generator.

The function time.After is part of the standard library;
it waits for a specified time to elapse and then sends the current time
on the returned channel.

Concurrency (example)

We end with a small but complete example to show how the pieces fit together.
It’s draft code for a server accepting Work requests
through a channel. Each request is served in a separate goroutine.
The Work struct itself contains a channel
used to return a result.