- Introduction
- Program Structure
- Go Comments
- Data Types
- Type Assertion
- Type Switch
- Type Conversions
- Basic Operators
- Methods
- Control Flow
- Console Printing
- Variables
- Functions
- Keywords
- The Go Programming Language Specification
- Interactive Go Tour
- Builtin functions
- Reflect Package
- Go Examples and Cheatsheets
- The Go Playground is an online repl that makes it easy to test small scripts
- For a local repl, checkout the gore project
Every Go program is made up of packages. Programs start running in package main
.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10).Seed(1023))
}
As you can see above, this program is using the fmt
and math/rand
packages.
By convention, the package name is the same as the last element of the import path.
For instance, the math/rand
package comprises files that begin with the statement
package rand
.
In Go, a function is exported if it begins with a capital letter.
Comment | Definition |
---|---|
// comment | single-line comment |
/* comment */ | multi-line comment |
Variable type | Definition |
---|---|
bool | true/false |
string | represents a set of string values eg. "string" or string ; strings are immutable |
array | numbered sequence of elements of a single type; a := [2]int{1, 3} |
slice | dynamically-sized, flexible view into the elements of an array; b := []int{1, 2, 3} |
pointer | holds the memory address of a value; var p *int |
struct | a collection of fields; the definition of an objects structure |
map | a key value object |
function | a unit of code that works on various inputs |
interface | set of method signatures |
uint | 32 or 64 bits depending on implementation |
uint8 | the set of all unsigned 8-bit integers (0 to 255) |
uint16 | the set of all unsigned 16-bit integers (0 to 65535) |
uint32 | the set of all unsigned 32-bit integers (0 to 4294967295) |
uint64 | the set of all unsigned 64-bit integers (0 to 18446744073709551615) |
int | same size as uint, 32 or 64 bits depending on implementation |
int8 | the set of all signed 8-bit integers (-128 to 127) |
int16 | the set of all signed 16-bit integers (-32768 to 32767) |
int32 | the set of all signed 32-bit integers (-2147483648 to 2147483647) |
int64 | the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807) |
uintptr | an unsigned integer large enough to store the uninterpreted bits of a pointer value |
byte | alias for uint8 |
rune | alias for int32, represents a Unicode code point |
float32 | the set of all IEEE-754 32-bit floating-point numbers |
float64 | the set of all IEEE-754 64-bit floating-point numbers |
complex64 | the set of all complex numbers with float32 real and imaginary parts |
complex128 | the set of all complex numbers with float64 real and imaginary parts |
The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.
`abc` // same as "abc"
`\n
\n` // same as "\\n\n\\n"
"\n"
"\"" // same as `"`
"Hello, world!\n"
"日本語"
"\u65e5本\U00008a9e"
"\xff\u00FF"
"\uD800" // illegal: surrogate half
"\U00110000" // illegal: invalid Unicode code point
These examples all represent the same string:
"日本語" // UTF-8 input text
`日本語` // UTF-8 input text as a raw literal
"\u65e5\u672c\u8a9e" // the explicit Unicode code points
"\U000065e5\U0000672c\U00008a9e" // the explicit Unicode code points
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // the explicit UTF-8 bytes
The type [n]T
is an array of n
values of type T
. An arrays length is part of its
type so arrays cannot be resized.
var a [10]int // variable a is array of 10 integers
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
// a == [Hello World]
primes := [6]int{2, 3, 5, 7, 11, 13}
// primes == [2 3 5 7 11 13]
}
A slice is a dynamically-sized, flexible view into the elements of an array. []T
Slices do not store data; they are like references to arrays.
Slices with no values are nil; var s []int; s == nil
Multiple ways to create slices:
- Specifying the low and high indices of an array
primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] // [3 5 7] // You can also omit the indices and the slice defaults to 0 and the length of the array var t []int = primes[:] // [2 3 5 7 11 13] var u []int = primes[:4] // [2 3 5 7] var v []int = primes[1:] // [3 5 7 11 13]
- Slice literals are like arrays without the length
- They automatically create an array and a slice that references it
// Array literal [3]bool{true, true, false} // [true true false] // Slice literal; creates the same array as above and slice to reference it []bool{true, true, false} // [true true false] s := []struct { i int b bool }{ {2, true}, {3, false}, {5, true}, {7, true}, {11, false}, {13, true}, } // [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
- They automatically create an array and a slice that references it
- Creating a slice with make
- The
make
function allocates a zeroed array and returns a slice that refers to that array
a := make([]int, 5) // len=5 cap=5 [0 0 0 0 0] b := make([]int, 0, 5) // b len=0 cap=5 [] c := b[:2] // c len=2 cap=5 [0 0] d := c[2:5] // len=3 cap=3 [0 0 0]
- The
A map is a key/value object store.
The zero value of a map is nil
. A nil
map has no keys, nor
can keys be added.
The make
function returns a map of the given type, initialized and ready for use.
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
} // map[Bell Labs:{40.68433 -74.39967}]
Map literals are like struct literals, but the keys are required.
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
} // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
// If the top-level type is just a type name, you can omit it from the elements of the literal.
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
} // map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
- Insert or update an element in map
m
m[key] = elem
- Retrieve an element
elem = m[key]
- Delete an element
delete(m, key)
- Test tha a key is present with a two-value assignment
elem, ok = m[key] // If key is in m, ok is true. If not, ok is false. // If key is not in the map, then elem is the zero value of the map's element type. // If elem or ok have not yet been declared you could use a short declartation form. elem, ok := m[key]
Return a map where each word has a count of how many times that word is in a string
package main
import (
"strings"
"golang.org/x/tour/wc"
)
func WordCount(s string) map[string]int {
var res = make(map[string]int)
var words []string
words = strings.Split(s, " ")
for _, v := range words {
res[v] += 1
}
return res
}
func main() {
wc.Test(WordCount)
}
A pointer holds the memory address of a value.
The type *T
is a pointer to a T
value. Its zero value is nil
.
var p *int
The &
operator generates a pointer to its operand. The *
operator denotes a pointers
underlying value.
i := 42
p = &i // *p == 42
*p = *p + 1 // *p == i == 43
A struct
is a collection of fields. (Like naming objects in JS?)
type Vertex struct {
X int
Y int
}
Struct fields are accessed using dot notation.
type Vertex struct {
X int
Y int
}
v := Vertex{1, 2}
v.X = 4
// v == {4, 2}
Pointers to structs can also be accessed with dot notation.
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
// v == {1000000000 2}
}
You can also create a struct by listing the values of is fields.
type Vertex struct {
X, Y int
}
var v1 = Vertex{1, 2} // {1 2}
var v2 = Vertex{X: 1} // {1 0}
var v3 = Vertex{} // {0 0}
var p = &Vertex{1, 2} // &{1 2} has type *Vertex
Functions are values too. They can be passed around like other values.
Function values may be used as function arguments and return values.
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12)) // 13
fmt.Println(compute(hypot)) // 5
fmt.Println(compute(math.Pow)) // 81
}
Set of method signatures.
Example interface that implements function Length
package main
import (
"fmt"
)
type Lengthsize interface {
Length() int
}
func main() {
var b Lengthsize
var c Lengthsize
g := MyString("Hello")
h := MySlice{"hello", "world"}
b = g // g MyString implements Length
c = h // h MySlice implements Length
fmt.Println(b.Length())
fmt.Println(c.Length())
}
type MyString string
type MySlice []string
func (s MyString) Length() int {
return len(s)
}
func (s MySlice) Length() int {
return len(s)
}
The Stringer interface implemented by the fmt package allows you to implement a method on your types to format them as a string.
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
fmt.Println(a) // Arthur Dent (42 years)
}
Type assertion provides access to an interface value's underlying concrete value
t := i.(T)
var i interface{} = "hello"
s := i.(string)
fmt.Println(s) // hello
A type switch is a construct that permits several type assertions in series.
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21) // Twice 21 is 42
do("hello") // "hello" is 5 bytes long
do(true) // I don't know about type bool!
}
T(v)
converts the value v
to the type T
.
Numeric conversion examples:
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
// Or
i := 42
f := float64(i)
u := uint(f)
String conversion requires the strconv
package.
- Convert string to integer with the Atoi function
i, err := strconv.Atoi("-42")
- Convert integer to string with Itoa function
s := strconv.Itoa(-42)
String too boolean conversion requires the strconv
package.
To convert a string into a boolean use the ParseBool method. It returns the boolean value
represented by the string. It accepts as parameter 1
, t
, T
, TRUE
, true
, True
,
0
, f
, F
, FALSE
, false
, False
. Any other value returns an error.
a, err := strconv.ParseBool("1") // true
b, err := strconv.ParseBool("t") // true
c, err := strconv.ParseBool("T") // true
d, err := strconv.ParseBool("TRUE") // true
e, err := strconv.ParseBool("true") // true
f, err := strconv.ParseBool("True") // true
g, err := strconv.ParseBool("0") // false
h, err := strconv.ParseBool("f") // false
i, err := strconv.ParseBool("F") // false
j, err := strconv.ParseBool("FALSE") // false
k, err := strconv.ParseBool("false") // false
l, err := strconv.ParseBool("False") // false
Operators | Usage |
---|---|
&& | and |
! | not |
== | equal |
!= | not equal |
< | less than |
| greater than
<= | less than or equal
= | greater than or equal
-
| addition
-
| subtraction
-
| multiplication
/ | division % | remainder (integers) & | bitwise AND | | bitwise OR ^ | bitwize XOR &^ | bit clear (AND NOT) << | left shift
| right shift
Method | Action |
---|---|
len | returns the length of v, according to it's type len("Hello") == 5 |
cap | returns the capacity v, according to it's type cap([4]{1,2,3,4}) == 4 |
append | appends new elements to a slice s := []int{1,2}; s = append(s, 3, 4) |
reflect.TypeOf | returns type of data reflect.TypeOf("a") == string |
reflect.DeepEqual | determins if two values are deeply equal |
if condition {
// do something
} else {
// do something different
}
// Example
if x > 0 {
x++
} else {
x = 1
}
If can start with a short statement before the condition, but any variables declared in
that statement are only in scope of the if
.
if v := math.Pow(x, n); v < lim {
return v
}
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
// sum == 45
The init and post statements are optional in Go, so the for loop can be used as a while loop too.
sum := 1
for sum < 1000 {
sum += sum
}
range
is another form of the for
loops that iterates over a slice of map.
var nums = []int{1, 2, 4}
func main() {
for i, v := range nums {
fmt.Printf("%d - %d\n", i, v)
}
}
// 0 - 1
// 1 - 2
// 2 - 4
Go only runs the selected case, not all the cases that follow, so the break
statement
required in some other languages is not needed in Go.
- Example of switch with an init statement and a condition
switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X") case "linux": fmt.Println("Linux") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s\n" os) }
- Example switch statement with no condition
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.") }
A defer statement defers the execution of a function until the surrounding function returns.
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
// hello
// world
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
// counting
// done
// 9
// 8
// 7
// 6
// 5
// 4
// 3
// 2
// 1
// 0
- Print the type of a variable
v := "42" t := 42 fmt.Printf("v is of type %T\nt is of type %T\n", v, t) //v is of type string //t is of type int
Variables can be declared multiple ways in Go; var
, :=
, const
- Using the
var
keyword and specifying a typevar x int var a, b, c string
- Using the short assignement statement
:=
with implicit type- Note that this assignment opartor is only available inside a function
k := 3 isAlive := true i, hasAccount, taco := 42, true, "burrito"
- Using the
const
keyword to create a constant- Constants can be character, string, boolean, or numeric values.
- Constants cannot be declared using the := syntax
const Pi = 3.14
Variables declared without an explicit initial value are given their zero value.
The zero value is:
numeric types: 0
boolean type: false
strings: "" (the empty string)
Functions are declared with the func
keyword, can accept zero or more arguments, and can return zero or more values.
When two ore more consecutive named function parameters share a types, you can omit the type from all by the last.
x int, y int -> x, y int
func name(a type, b type, ...) (return-type, return-type2, ...) {
// Do something here and return a value of type return-type
}
-
Example with one return value
func add(x int, y int) int { return x + y } // OR func add (x, y int) int { return x + y }
-
Example with multiple return values
func swap(x, y string) (string, string) { return y, x }
-
Example with named return values
- In the next example, we are using named return values and a "naked" return
- Note that the return is not actually specifying what to return, but the values being set in the function match the names of the return values
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return }
The following keywords are reserved and may not be used as identifiers.
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var