${GOPATH}/bin/gotour
main
package.import “math/rand”
imports from math/rand/rand.go
: package rand import ( "math" )
import ( "fmt" "math" )
func main() { fmt.Println(math.Pi) }
math/const.go
: // Mathematical constants. const ( E = 2.71828182845904523536028747135266249775724709369995957496696763 // https://oeis.org/A001113 Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // https://oeis.org/A000796 Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // https://oeis.org/A001622 ... )
func add(x int, y int) int { return x + y }
func add(x, y int) int { return x + y }
func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) }
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return } func main() { fmt.Println(split(17)) }
Naked return statements should be used only in short functions, as with the example shown here. They can harm readability in longer functions.
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // alias for uint8 rune // alias for int32 // represents a Unicode code point float32 float64 complex64 complex128
Type of list of variables is at the end:
var c, python, java bool
var i, j int = 1, 2
Inside functions, implicit short declarations using :=
:
func main() { var i, j int = 1, 2 k := 3 c, python, java := true, false, "no!" fmt.Println(i, j, k, c, python, java) }
Can be “factored” into blocks:
package main import ( "fmt" "math/cmplx" ) var ( ToBe bool = false MaxInt uint64 = 1<<64 - 1 z complex128 = cmplx.Sqrt(-5 + 12i) )
Uninitialized variables are given their corresponding zero value:
No implicit type conversion, must be explicit:
var i int = 42 var f float64 = float64(i) var u uint = uint(f) i := 42 f := float64(i) u := uint(f)
Print the type of a variable:
func main() { v := 42.1 // change me! fmt.Printf("v is of type %T\n", v) }
const Pi = 3.14
Go's only looping construct:
func main() { sum := 0 for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) }
for ; sum < 1000; { sum += sum }
Here's Go's while loop:
for sum < 1000 { sum += sum }
Go's infinite loop:
for { }
func sqrt(x float64) string { if x < 0 { return sqrt(-x) + "i" } return fmt.Sprint(math.Sqrt(x)) }
Open with a short initializer statement:
func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } return lim }
Variables declared inside an if short statement are also available inside any of the else blocks.
func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } else { fmt.Printf("%g >= %g\n", v, lim) } // can't use v here, though return lim }
Go's switch cases need not be constants, and the values involved need not be integers.
Top to bottom, executes only one possibility:
func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) } }
Switch with no condition same as switch true
– cleaner to write if-then-else:
func main() { t := time.Now() switch { case t.Hour() < 12: fmt.Println("Good morning!") case t.Hour() < 17: fmt.Println("Good afternoon.") default: fmt.Println("Good evening.") } }
func main() { defer fmt.Println("world") fmt.Println("hello") }
Multiple defers are stacked so executed in reverse order:
func main() { fmt.Println("counting") for i := 0; i < 10; i++ { defer fmt.Println(i) } fmt.Println("done") }
Go has no pointer arithmetic; zero value is nil
.
Declaring simple pointers:
var p *int
Initialize at the same time with :=
:
func main() { i, j := 42, 2701 p := &i // point to i fmt.Println(*p) // read i through the pointer *p = 21 // set i through the pointer fmt.Println(i) // see the new value of i p = &j // point to j *p = *p / 37 // divide j through the pointer fmt.Println(j) // see the new value of j }
type Vertex struct { X int Y int } func main() { fmt.Println(Vertex{1, 2}) }
type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} v.X = 4 fmt.Println(v.X) }
type Vertex struct { X int Y int } func main() { v := Vertex{1, 2} p := &v p.X = 1e9 // no need to dereference fmt.Println(v) }
type Vertex struct { X, Y int } var ( v1 = Vertex{1, 2} // has type Vertex v2 = Vertex{X: 1} // Y:0 is implicit v3 = Vertex{} // X:0 and Y:0 p = &Vertex{1, 2} // has type *Vertex ) func main() { fmt.Println(v1, p, v2, v3) }
Simple declaration (arrays cannot be resized):
func main() { var a [2]string a[0] = "Hello" a[1] = "World" fmt.Println(a[0], a[1]) fmt.Println(a) primes := [6]int{2, 3, 5, 7, 11, 13} fmt.Println(primes) }
An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array. In practice, slices are much more common than arrays.
The type []T
is a slice with elements of type T
:
func main() { primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] fmt.Println(s) }
A slice does not store any data, it just describes a section of an underlying array.
Changing the elements of a slice modifies the corresponding elements of its underlying array.
Other slices that share the same underlying array will see those changes.
func main() { q := []int{2, 3, 5, 7, 11, 13} fmt.Println(q) r := []bool{true, false, true, true, false, true} fmt.Println(r) s := []struct { i int b bool }{ {2, true}, {3, false}, {5, true}, {7, true}, {11, false}, {13, true}, } fmt.Println(s) }
a[0:10] a[:10] a[0:] a[:]
The length of a slice is the number of elements it contains.
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.
The length and capacity of a slice s can be obtained using the expressions len(s)
and cap(s)
.
func main() { var s []int fmt.Println(s, len(s), cap(s)) if s == nil { fmt.Println("nil!") } }
func main() { a := make([]int, 5) printSlice("a", a) b := make([]int, 0, 5) printSlice("b", b) c := b[:2] printSlice("c", c) d := c[2:5] printSlice("d", d) }
func main() { // Create a tic-tac-toe board. board := [][]string{ []string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, } // The players take turns. board[0][0] = "X" board[2][2] = "O" board[1][2] = "X" board[1][0] = "O" board[0][2] = "X" for i := 0; i < len(board); i++ { fmt.Printf("%s\n", strings.Join(board[i], " ")) } }
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %d\n", i, v) } }
func main() { pow := make([]int, 10) for i := range pow { pow[i] = 1 << uint(i) // == 2**i } for _, value := range pow { fmt.Printf("%d\n", value) } }
func adder() func(int) int { sum := 0 // closure part return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), neg(-2*i), ) } }
Fibonacci closure:
func fibonacci() func() int { current, next := 0, 1 return func() int { current, next = next, next+current return current } }
Non-method Abs()
function for Vertex
, which takes a Vertex
as a regular argument (no polymorphism)
type Vertex struct { X, Y float64 } func Abs(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(Abs(v)) }
Go does not support classes; rather, you can define methods on types by adding a receiver argument to a function:
type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { // receiver argument return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) // style 1 fmt.Println(Vertex{3,4}.Abs()) // style 2 }
You can declare a method on non-struct types, too. Below, we see a numeric type MyFloat
with an Abs
method:
type MyFloat float64 // introduces a new type, not just an alias func (f MyFloat) Abs() float64 { if f < 0 { return float64(-f) } return float64(f) } func main() { f := MyFloat(-math.Sqrt2) fmt.Println(f.Abs()) }
You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int
).
Call-by-value function, which makes a copy of the argument:
package main import ( "fmt" ) type Vertex struct { X, Y float64 } func Scale(v Vertex, f float64) Vertex { v.X = v.X * f v.Y = v.Y * f return v } func main() { v := Vertex{3, 4} fmt.Println(v) fmt.Println(Scale(v, 10)) fmt.Println(v) } {3 4} {30 40} {3 4}
Pointer-based call:
package main import ( "fmt" ) type Vertex struct { X, Y float64 } func Scale(v *Vertex, f float64) { v.X = v.X * f v.Y = v.Y * f } func main() { v := Vertex{3, 4} fmt.Println(v) Scale(&v, 10) fmt.Println(v) } {3 4} {30 40}
Notes about the above: