Booleans
var ok bool = true
var done = false
Operators: &&, ||, !. Short-circuit evaluation. There is no implicit
conversion between bool and integers — if 1 { ... } is a compile error.
Numeric types
| Family | Types | Notes |
|---|---|---|
| Signed | int8 int16 int32 int64 |
Two's complement. |
| Unsigned | uint8 uint16 uint32 uint64 uintptr |
uint8 is also byte. |
| Platform | int, uint |
32 or 64 bits depending on platform. |
| Float | float32 float64 |
IEEE 754. Default literal: float64. |
| Complex | complex64 complex128 |
Rarely used outside numerical code. |
| Aliases | byte = uint8, rune = int32 |
rune represents a Unicode code point. |
Conversions are always explicit:
var i int = 65
var f float64 = float64(i)
var u uint = uint(f)
var c rune = rune(i) // 'A'
Mixing types in arithmetic without conversion is a compile error.
Overflow
Signed integer overflow wraps (defined behaviour). Floating point follows
IEEE 754. Use math/big for arbitrary precision.
Strings
A string is an immutable read-only slice of bytes. By convention it
holds UTF-8 text but can hold any bytes.
s := "héllo" // UTF-8: 6 bytes
fmt.Println(len(s)) // 6, not 5
for i, r := range s { // i is the byte index, r is the rune
fmt.Printf("%d: %c\n", i, r)
}
bs := []byte(s) // copy to mutable byte slice
rs := []rune(s) // decode to rune slice (length 5)
Concatenation with + is fine for a few strings; for many use
strings.Builder:
var b strings.Builder
for i := 0; i < 1000; i++ {
b.WriteString("x")
}
result := b.String()
Useful packages:
strings:Contains,Split,Join,ReplaceAll,ToUpper,Builder.strconv:Itoa,Atoi,FormatFloat,ParseInt.fmt:Sprintf,Sprintln.unicode/utf8: low-level UTF-8 helpers.
Arrays
Arrays in Go are fixed length and the length is part of the type:
var a [3]int // [0 0 0]
b := [3]int{1, 2, 3}
c := [...]int{1, 2, 3, 4} // length inferred: 4
Arrays are value types: assigning or passing them copies the whole array. You will rarely use arrays directly; you almost always want a slice.
Slices
A slice is a small struct: {pointer, length, capacity}. It refers to a
backing array.
s := []int{1, 2, 3, 4, 5}
fmt.Println(len(s), cap(s)) // 5 5
t := s[1:4] // {2,3,4}, len=3, cap=4 (shares backing array!)
t[0] = 99 // also modifies s[1]
fmt.Println(s) // [1 99 3 4 5]
make, append, growth
s := make([]int, 0, 8) // len 0, cap 8
s = append(s, 1, 2, 3)
s = append(s, more...) // spread
// To copy instead of alias:
dst := make([]int, len(src))
copy(dst, src)
append may reallocate if cap isn't enough; the new capacity roughly
doubles for small slices and grows by ~25% for large ones (implementation
detail, not part of the spec).
Common slice idioms
// remove element at index i, preserving order:
a = append(a[:i], a[i+1:]...)
// remove element at index i, swapping with the last (O(1), order changes):
a[i] = a[len(a)-1]; a = a[:len(a)-1]
// insert v at index i:
a = append(a[:i], append([]int{v}, a[i:]...)...)
// reverse:
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
Maps
Maps are reference types implemented as hash tables.
m := map[string]int{"a": 1, "b": 2}
m["c"] = 3
v, ok := m["x"] // v=0, ok=false
delete(m, "a")
for k, v := range m { // iteration order is RANDOMIZED on purpose
fmt.Println(k, v)
}
A nil map can be read from (returns the zero value) but writing to it
panics. Always create with a literal or make:
var m map[string]int
m["x"] = 1 // PANIC
m = make(map[string]int)
m["x"] = 1 // OK
Map keys must be comparable (no slices, maps, or functions as keys).
Structs
type Point struct {
X, Y int
}
p := Point{X: 1, Y: 2}
q := Point{3, 4} // positional, fragile
fmt.Println(p.X, q.Y)
type Person struct {
Name string
Age int
Addr struct { // anonymous nested struct
City string
}
}
Structs are value types. Assigning copies the struct.
Embedding (composition)
type Animal struct{ Name string }
func (a Animal) Speak() string { return a.Name + " makes a sound" }
type Dog struct {
Animal // embedded — fields and methods are "promoted"
Breed string
}
d := Dog{Animal{"Rex"}, "Lab"}
fmt.Println(d.Name, d.Speak()) // promoted access
This is how Go does "inheritance-like" reuse.
Pointers (preview)
p := &Point{1, 2} // *Point
p.X = 10 // automatic dereference
fmt.Println((*p).Y) // explicit dereference also works
Pointers are covered fully in Chapter 8.
Run the example
go run ./part1-language/examples/04_types