Basics
Updated: November 24, 2025
Learn the basic components that make up the Go language.
Table of Contents
- Arrays
- Calls
- Channels
- Concurrency
- Constants
- Conversions
- Errors
- Functions
- Interfaces
- Loops
- Maps
- Methods
- Pointers
- Range
- Scope
- Slices
- Structs
- Switches
- Syntax
- Types
- Variables
- Zero Values
Arrays
- Fixed-size sequences of elements of the same type
- Length is part of the type, cannot change
var a [5]int // array of 5 ints
a[4] = 100
fmt.Println(len(a)) // 5
Calls
- Function calls execute functions with arguments
- Can return multiple values
- Arguments passed by value (copied)
result := add(1, 2)
x, y := swap("hello", "world")
Channels
- Channels are typed conduits for sending and receiving values
- Used for communication between goroutines
- Can be buffered or unbuffered
// Declaring and initializing
c := make(chan int)
// Sending a value on a channel
c <- 1
// Receiving a value from a channel
x = <-c
// Buffered channel
ch := make(chan int, 2)
Concurrency
- Goroutines: lightweight threads managed by Go runtime
- Channels for communication and synchronization
- Select statement for multiplexing channels
go func() { fmt.Println("goroutine") }()
ch := make(chan int)
go func() { ch <- 1 }()
x := <-ch
select {
case msg1 := <-ch1:
fmt.Println("Received", msg1)
case msg2 := <-ch2:
fmt.Println("Received", msg2)
}
Constants
- Constants are immutable values known at compile time
- Can be typed or untyped
- iota for enumerated constants
const Pi = 3.14159
const (
A = iota // 0
B // 1
C // 2
)
Conversions
- Explicit type conversions required between different types
- Expression T(v) converts value v to type T
- Some conversions may lose information
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
Errors
- Errors are values that implement the error interface
- Use errors.New() or fmt.Errorf() to create errors
- Handle errors explicitly, don’t ignore them
type error interface {
Error() string
}
var ErrNotFound = errors.New("not found")
func doSomething() error {
return fmt.Errorf("something went wrong: %v", err)
}
Functions
- Functions are first-class citizens in Go
- Can take zero or more arguments
- Can return multiple values
- Support closures and higher-order functions
func add(x, y int) int {
return x + y
}
func swap(x, y string) (string, string) {
return y, x
}
func apply(f func(int, int) int, x, y int) int {
return f(x, y)
}
Interfaces
- Interfaces define method sets that types must implement
- Types implement interfaces implicitly
- Empty interface{} can hold any value
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
var r Reader = os.Stdin
Loops
- Go has only one loop construct: for
- Can be used as traditional for, while, or foreach
// Traditional for
for i := 0; i < 10; i++ {
fmt.Println(i)
}
// While-like
i := 0
for i < 10 {
fmt.Println(i)
i++
}
// Infinite loop
for {
// do something
}
Maps
- Maps are key-value stores
- Keys must be comparable types
- Not safe for concurrent access
m := make(map[string]int)
m["key"] = 42
value := m["key"]
delete(m, "key")
_, exists := m["key"]
Methods
- Methods are functions with receivers
- Receivers can be value or pointer types
- Define behavior for types
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X *= f
v.Y *= f
}
Pointers
- Pointers hold memory addresses of values
- Dereference with * operator
- Use & to get address of value
var p *int
i := 42
p = &i
fmt.Println(*p) // 42
*p = 21 // changes i
Range
- Range iterates over arrays, slices, maps, channels
- Returns index and value for slices/arrays/maps
- Returns received value for channels
nums := []int{1, 2, 3}
for i, num := range nums {
fmt.Println(i, num)
}
m := map[string]int{"a": 1, "b": 2}
for key, value := range m {
fmt.Println(key, value)
}
Scope
- Variables have lexical scope
- Package-level variables accessible throughout package
- Function-level variables scoped to function
- Block-level variables scoped to block
var global = "global" // package scope
func main() {
local := "local" // function scope
{
block := "block" // block scope
}
}
Slices
- Slices are dynamic arrays
- Reference to underlying array
- Length and capacity
s := make([]int, 5) // len=5, cap=5
s = append(s, 6) // len=6, cap=10 (doubled)
sub := s[1:3] // slice from index 1 to 3
Structs
- Structs are collections of fields
- Fields can be exported (capitalized) or unexported
- Can embed other structs
type Person struct {
Name string
Age int
}
type Employee struct {
Person
Salary int
}
p := Person{Name: "Alice", Age: 30}
Switches
- Switch statements provide multi-way branching
- Can switch on values, types, or conditions
- Cases can have multiple values
switch day := "monday"; day {
case "monday", "tuesday":
fmt.Println("Weekday")
case "saturday", "sunday":
fmt.Println("Weekend")
default:
fmt.Println("Invalid day")
}
// Type switch
var i interface{} = "hello"
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))
}
Syntax
- Go uses curly braces for blocks
- Semicolons are optional, inserted automatically
- Names are exported if capitalized
// Single line comment
/* Multi-line
comment */
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Types
- Go is statically typed
- Basic types: bool, string, numeric types
- Composite types: arrays, slices, maps, structs, interfaces
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64
complex64 complex128
byte // alias for uint8
rune // alias for int32
Variables
- Variables declared with var or short := syntax
- Type can be inferred
- Multiple variables can be declared together
var i int = 42
var f float64 = 3.14
x := 42 // inferred as int
a, b := 1, 2 // multiple assignment
Zero Values
- Variables declared without initialization get zero values
- Zero value depends on type
var i int // 0
var f float64 // 0.0
var b bool // false
var s string // ""
var p *int // nil