Go Language Basics Cheatsheet
Master the fundamentals of Go (Golang) for rapid development, covering syntax, core concepts, and essential commands for version 1.22.
Master the fundamentals of Go (Golang) for rapid development, covering syntax, core concepts, and essential commands for version 1.22.
Go, often referred to as Golang, is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It emphasizes simplicity, reliability, and efficiency, making it ideal for building scalable network services, command-line tools, and cloud infrastructure. Go includes built-in concurrency features and a robust standard library.
Current Stable Version: Go 1.22 Install: Download from go.dev/dl/ or use a package manager.
To get up and running with Go, you’ll first need to install the Go toolchain and then create your first program.
Install Go 1.22: Download the appropriate installer for your operating system (Linux, macOS, Windows) from the official Go downloads page: go.dev/dl/. Follow the installation instructions provided on the Go website: go.dev/doc/install.
# Install Go 1.22 via Homebrew
brew install [email protected]
.tar.gz (Linux/macOS) or .zip (Windows) archive, extract it to /usr/local (Linux/macOS) or C:\Go (Windows), and configure your PATH environment variable.Verify Installation: Open a new terminal or command prompt and run:
# Check the Go version
go version
You should see output similar to go version go1.22.x <os>/<arch>.
Your First Go Program (Hello World): Create a new directory for your project:
# Create a project directory
mkdir myapp
cd myapp
Initialize a Go module (this manages dependencies):
# Initialize a Go module
go mod init myapp
Create a file named main.go with the following content:
// main.go
package main // Declares the package as 'main', making it an executable program
import "fmt" // Imports the "fmt" package for formatted I/O
func main() { // The entry point of the program
fmt.Println("Hello, Go 1.22!") // Prints a string to the console
}
Run Your Program:
From your project directory (myapp), execute the program:
# Run the Go program
go run main.go
Output:
Hello, Go 1.22!
Understanding these fundamental concepts is crucial for working effectively with Go.
| Concept | Description |
|---|---|
| Packages | Go programs are organized into packages. A main package and main function define an executable program. Other packages are libraries. |
| Imports | The import keyword brings other packages into scope. Standard library packages (like fmt) are commonly used. |
| Functions | Blocks of code designed to perform a specific task. main() is the entry point. Functions can accept arguments and return values. |
| Variables | Explicitly declared with var or short declaration :=. Statically typed but often inferred. Zero-valued by default. |
| Types | Go is statically typed. Basic types include int, float64, bool, string. Composite types are struct, array, slice, map, interface, chan. |
| Goroutines | Lightweight, independently executing functions. Go’s concurrency model based on Communicating Sequential Processes (CSP). |
| Channels | Typed conduits through which goroutines can send and receive values, ensuring safe communication and synchronization. |
| Error Handling | Go functions return errors explicitly as the last return value. Errors are checked with if err != nil. |
This section covers the most common Go syntax and commands you’ll use daily.
go Command# Compile and run a Go program
go run main.go
# Compile a Go program into an executable binary
go build -o myprogram main.go
# ./myprogram (on Linux/macOS) or myprogram.exe (on Windows)
# Download and install a package (usually handled by go mod tidy)
go get github.com/some/package
# Add missing and remove unused module dependencies
go mod tidy
# Format your Go code automatically (use often!)
go fmt ./...
# Run tests
go test ./...
# View package documentation in your browser
go doc fmt.Println
package main
import "fmt"
func main() {
// Declare a variable, zero-valued by default (e.g., int is 0, string is "")
var name string
name = "Alice"
fmt.Println("Name:", name)
// Declare and initialize
var age int = 30
fmt.Println("Age:", age)
// Short variable declaration (type inferred), only inside functions
city := "New York"
fmt.Println("City:", city)
// Multiple variable declarations
var (
height = 1.75
weight = 70.5
)
fmt.Println("Height:", height, "Weight:", weight)
// Constants
const PI = 3.14159
const GREETING = "Hello"
fmt.Println("PI:", PI, "Greeting:", GREETING)
// Untyped constants
const untypedConst = 100 // Type determined by usage
var typedVar int = untypedConst
fmt.Println("Typed var:", typedVar)
}
package main
import "fmt"
func main() {
// Integers
var i int = 10 // Default int size varies by system (32 or 64-bit)
var j int32 = -20 // 32-bit integer
var k uint = 100 // Unsigned integer
fmt.Printf("i: %T %v, j: %T %v, k: %T %v\n", i, i, j, j, k, k)
// Floating-point numbers
var f1 float32 = 3.14 // Single-precision float
var f2 float64 = 3.1415926535 // Double-precision float (default for literals)
fmt.Printf("f1: %T %v, f2: %T %v\n", f1, f1, f2, f2)
// Booleans
var b1 bool = true
b2 := false
fmt.Printf("b1: %T %v, b2: %T %v\n", b1, b1, b2, b2)
// Strings (UTF-8 encoded)
var s1 string = "Hello, Go"
s2 := `Multi-line
string literal`
fmt.Printf("s1: %T %q, s2: %T %q\n", s1, s1, s2, s2)
fmt.Println("Length of s1:", len(s1))
}
if, for, switchpackage main
import "fmt"
func main() {
// If-Else
x := 10
if x > 5 {
fmt.Println("x is greater than 5")
} else if x == 5 {
fmt.Println("x is 5")
} else {
fmt.Println("x is less than 5")
}
// If with a short statement
if y := 20; y%2 == 0 { // y is scoped to the if-else block
fmt.Println("y is even")
} else {
fmt.Println("y is odd")
}
// For loop (Go's only loop construct)
// Basic for loop (like C's for)
for i := 0; i < 3; i++ {
fmt.Println("For loop iteration:", i)
}
// For as a while loop
sum := 1
for sum < 10 {
sum += sum
fmt.Println("Sum:", sum)
}
// Infinite loop (use with break or return)
// for {
// fmt.Println("Infinite loop - press Ctrl+C to stop")
// }
// For-range over slices, arrays, strings, maps, channels
numbers := []int{10, 20, 30}
for index, value := range numbers {
fmt.Printf("Index: %d, Value: %d\n", index, value)
}
// Go 1.22: For-range over integers
fmt.Println("Countdown:")
for i := range 3 { // i will be 0, 1, 2
fmt.Println(3 - i)
}
// Switch statement
day := "Monday"
switch day {
case "Saturday", "Sunday":
fmt.Println("It's the weekend!")
case "Monday":
fmt.Println("It's Monday, time to work.")
default:
fmt.Println("It's a weekday.")
}
// Switch without a condition (like if/else if)
score := 85
switch {
case score >= 90:
fmt.Println("Grade A")
case score >= 80:
fmt.Println("Grade B")
default:
fmt.Println("Grade C or lower")
}
}
package main
import "fmt"
// Function that takes two integers and returns their sum
func add(a int, b int) int {
return a + b
}
// Function with named return values
func subtract(a, b int) (result int) { // Type can be omitted for consecutive same-type params
result = a - b
return // "naked" return, returns the named result variable
}
// Function returning multiple values (often for value and error)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}
// Variadic function (takes a variable number of arguments)
func sumAll(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
fmt.Println("5 + 3 =", add(5, 3))
fmt.Println("10 - 4 =", subtract(10, 4))
quotient, err := divide(10.0, 2.0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("10 / 2 =", quotient)
}
_, err = divide(10.0, 0.0) // Ignore the first return value
if err != nil {
fmt.Println("Error:", err)
}
fmt.Println("Sum of 1, 2, 3:", sumAll(1, 2, 3))
fmt.Println("Sum of 5, 10, 15, 20:", sumAll(5, 10, 15, 20))
// Anonymous function (closure)
greeter := func(name string) {
fmt.Println("Hello,", name)
}
greeter("World")
}
package main
import "fmt"
func main() {
// Arrays: Fixed-size sequence of elements of the same type
var a [3]int // Declares an array of 3 integers, initialized to [0, 0, 0]
a[0] = 10
a[1] = 20
a[2] = 30
fmt.Println("Array a:", a, "Length:", len(a))
b := [3]int{1, 2, 3} // Declare and initialize
fmt.Println("Array b:", b)
c := [...]int{4, 5, 6, 7} // Compiler infers size
fmt.Println("Array c:", c, "Length:", len(c))
// Slices: Dynamic, flexible view into elements of an array
// Slices are much more common than arrays in Go
var s []int // Declares a nil slice
fmt.Println("Nil slice s:", s, "Length:", len(s), "Capacity:", cap(s))
s = append(s, 10) // Add elements
s = append(s, 20, 30)
fmt.Println("Slice s after append:", s, "Length:", len(s), "Capacity:", cap(s))
// Make a slice with initial length and capacity
// make([]type, length, capacity)
cities := make([]string, 2, 5) // len=2, cap=5
cities[0] = "London"
cities[1] = "Paris"
fmt.Println("Cities slice:", cities, "Length:", len(cities), "Capacity:", cap(cities))
cities = append(cities, "Tokyo") // Capacity might expand if needed
fmt.Println("Cities slice after append:", cities, "Length:", len(cities), "Capacity:", cap(cities))
// Slice literals
numbers := []int{1, 2, 3, 4, 5}
fmt.Println("Numbers slice:", numbers)
// Slicing (creates a new slice pointing to the same underlying array)
subSlice := numbers[1:4] // elements from index 1 (inclusive) to 4 (exclusive) -> [2, 3, 4]
fmt.Println("Sub-slice:", subSlice)
// Maps: Unordered collections of key-value pairs
// make(map[keyType]valueType)
temperatures := make(map[string]float64)
temperatures["NY"] = 25.5
temperatures["LA"] = 30.1
fmt.Println("Temperatures map:", temperatures)
// Map literal
ages := map[string]int{
"Alice": 30,
"Bob": 25,
}
fmt.Println("Ages map:", ages)
// Accessing a value
fmt.Println("Alice's age:", ages["Alice"])
// Check if a key exists
if val, ok := ages["Charlie"]; ok {
fmt.Println("Charlie's age:", val)
} else {
fmt.Println("Charlie not found.")
}
// Delete an element
delete(ages, "Bob")
fmt.Println("Ages after deleting Bob:", ages)
// Iterate over map
for name, age := range ages {
fmt.Printf("%s is %d years old\n", name, age)
}
}
package main
import "fmt"
// Define a struct (a collection of fields)
type Person struct {
Name string
Age int
City string
}
// Method associated with the Person type
// (p Person) is the receiver
func (p Person) Greet() string {
return fmt.Sprintf("Hello, my name is %s and I am %d years old.", p.Name, p.Age)
}
// Method that modifies a field (requires a pointer receiver)
func (p *Person) HappyBirthday() {
p.Age++
}
func main() {
// Create a struct instance
person1 := Person{"Alice", 30, "London"}
fmt.Println("Person 1:", person1)
fmt.Println(person1.Greet())
// Access fields
fmt.Println("Person 1's city:", person1.City)
// Create a struct instance with named fields
person2 := Person{
Name: "Bob",
Age: 25,
City: "Paris",
}
fmt.Println("Person 2:", person2)
// Use a method to modify the struct
person2.HappyBirthday() // Automatically takes the address of person2
fmt.Println("Person 2 after birthday:", person2)
// Anonymous struct
anonUser := struct {
ID int
Name string
}{
ID: 1,
Name: "Guest",
}
fmt.Println("Anonymous user:", anonUser)
}
package main
import "fmt"
func main() {
// Declare a variable
num := 10
fmt.Println("Value of num:", num) // Output: 10
// Declare a pointer to num
var p *int // p is a pointer to an integer
p = &num // Assign the memory address of num to p
fmt.Println("Address of num (&num):", &num) // Output: (memory address)
fmt.Println("Value of p (address it holds):", p) // Output: (same memory address)
fmt.Println("Value pointed to by p (*p):", *p) // Dereference p to get the value -> Output: 10
// Change value through pointer
*p = 20
fmt.Println("Value of num after pointer modification:", num) // Output: 20
// Creating a new pointer with `new`
newIntPtr := new(int) // Allocates memory for an int, returns a pointer to it, zero-valued
fmt.Println("Value pointed to by newIntPtr:", *newIntPtr) // Output: 0
*newIntPtr = 100
fmt.Println("Value pointed to by newIntPtr after assignment:", *newIntPtr) // Output: 100
}
Go uses explicit error return values, typically as the last return value, and checks them using if err != nil.
package main
import (
"errors"
"fmt"
)
// Function that might return an error
func doSomethingRisky(input int) (string, error) {
if input < 0 {
return "", errors.New("input cannot be negative") // Create a new error
}
if input > 100 {
return "", fmt.Errorf("input %d is too large", input) // Format an error
}
return fmt.Sprintf("Processed input: %d", input), nil // Return nil for no error
}
func main() {
result, err := doSomethingRisky(50)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Success:", result)
}
result, err = doSomethingRisky(-10)
if err != nil {
fmt.Println("Error:", err) // Output: Error: input cannot be negative
} else {
fmt.Println("Success:", result)
}
result, err = doSomethingRisky(200)
if err != nil {
fmt.Println("Error:", err) // Output: Error: input 200 is too large
} else {
fmt.Println("Success:", result)
}
}
// main.go (in myapp/ directory)
package main
import (
"fmt" // Standard library package for formatted I/O
"myapp/utils" // Local package, relative path from module root
"rsc.io/quote" // Third-party package (after `go get rsc.io/quote`)
)
func main() {
fmt.Println("Hello from main!")
fmt.Println(utils.SayHello("Go Developer")) // Call function from local package
fmt.Println(quote.Go()) // Call function from third-party package
}
// utils/greetings.go (in myapp/utils/ directory)
package utils // Declares this file belongs to the 'utils' package
import "fmt"
// SayHello is an exported function (starts with a capital letter)
func SayHello(name string) string {
return fmt.Sprintf("Greetings from utils package, %s!", name)
}
To run the above example:
myapp/main.gomyapp/utils/greetings.gogo mod init myapp in the myapp directory.go get rsc.io/quotego run main.gopackage main
import (
"fmt"
"os" // Provides access to operating system functionality
)
func main() {
// os.Args is a slice of strings, where os.Args[0] is the program name
if len(os.Args) > 1 {
fmt.Println("Arguments provided:")
for i, arg := range os.Args[1:] { // Iterate over arguments starting from the second one
fmt.Printf("Arg %d: %s\n", i+1, arg)
}
} else {
fmt.Println("No command-line arguments provided.")
}
}
Run:
go run main.go hello world
# Output:
# Arguments provided:
# Arg 1: hello
# Arg 2: world
package main
import (
"fmt"
"net/http" // Standard library for HTTP clients and servers
)
func main() {
// Handle requests to the root path "/"
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've hit %s\n", r.URL.Path)
})
// Handle requests to "/greet"
http.HandleFunc("/greet", func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name") // Get query parameter "name"
if name == "" {
name = "Guest"
}
fmt.Fprintf(w, "Greetings, %s!\n", name)
})
fmt.Println("Server starting on port 8080...")
// Start the server on port 8080
// http.ListenAndServe blocks until the server is shut down
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("Server failed:", err)
}
}
Run the server: go run main.go
Then open your browser or use curl:
http://localhost:8080http://localhost:8080/greethttp://localhost:8080/greet?name=Alicepackage main
import (
"fmt"
"time"
)
// Worker function that runs as a goroutine
func worker(id int, messages <-chan string, results chan<- string) {
for msg := range messages {
fmt.Printf("Worker %d received: %s\n", id, msg)
time.Sleep(time.Second) // Simulate work
results <- fmt.Sprintf("Worker %d finished: %s", id, msg)
}
}
func main() {
// Create channels for communication
messages := make(chan string) // Unbuffered channel for messages
results := make(chan string) // Unbuffered channel for results
// Start multiple workers as goroutines
for i := 1; i <= 3; i++ {
go worker(i, messages, results)
}
// Send messages to workers
for i := 1; i <= 5; i++ {
msg := fmt.Sprintf("Task %d", i)
messages <- msg
fmt.Println("Sent:", msg)
}
close(messages) // Close the messages channel when done sending
// Collect results from workers
for i := 1; i <= 5; i++ {
res := <-results
fmt.Println("Received result:", res)
}
close(results) // Close the results channel (optional here, as main exits)
fmt.Println("All tasks completed.")
}
while loop: Go only has the for keyword. You can use for <condition> for a while loop or for {} for an infinite loop.try-catch blocks. Errors are returned as the last value of a function, and you must explicitly check if err != nil. This encourages robust error management.func (p *Person)) instead of a value receiver (func (p Person)). Value receivers operate on a copy.package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Go 1.22 loop variable behavior:")
for i := 0; i < 3; i++ {
go func() {
// In Go 1.22+, 'i' here correctly captures the value of 'i' for each iteration
// In earlier versions, this would often print '3' multiple times
fmt.Println(i)
}()
}
time.Sleep(time.Millisecond * 10) // Give goroutines time to run
}
fmt for output: fmt.Println() for simple output, fmt.Printf() for formatted output (like C’s printf), and fmt.Sprintf() to format a string without printing it.int is 0, bool is false, string is "" (empty string), pointers are nil, slices and maps are nil.Source: z2h.fyi/cheatsheets/go-language-basics — Zero to Hero cheatsheets for developers.