Go Basics: Variables, Types, and Syntax
Variables
Declaration Methods
Go offers several ways to declare variables:
// Method 1: var with explicit type
var name string = "Alice"
var age int = 30
// Method 2: var with type inference
var city = "New York" // Go infers string
// Method 3: Short declaration (most common, only inside functions)
country := "USA"
count := 42
// Method 4: Multiple variables
var x, y, z int = 1, 2, 3
a, b, c := "hello", true, 3.14
// Method 5: Declaration block
var (
firstName string = "John"
lastName string = "Doe"
isActive bool = true
)
Zero Values
Uninitialized variables get a "zero value":
var i int // 0
var f float64 // 0.0
var b bool // false
var s string // "" (empty string)
var p *int // nil (for pointers, slices, maps, channels, functions, interfaces)
Constants
Constants are declared with const and cannot be changed:
const Pi = 3.14159
const (
StatusOK = 200
StatusError = 500
)
// iota: auto-incrementing constant generator
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
// iota with expressions
const (
_ = iota // 0 (ignored)
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
)
Basic Types
Numeric Types
// Integers
var i8 int8 // -128 to 127
var i16 int16 // -32768 to 32767
var i32 int32 // -2^31 to 2^31-1
var i64 int64 // -2^63 to 2^63-1
var i int // Platform dependent (32 or 64 bit)
// Unsigned integers
var u8 uint8 // 0 to 255 (alias: byte)
var u16 uint16 // 0 to 65535
var u32 uint32 // 0 to 2^32-1
var u64 uint64 // 0 to 2^64-1
var u uint // Platform dependent
// Floating point
var f32 float32 // IEEE-754 32-bit
var f64 float64 // IEEE-754 64-bit (preferred)
// Complex numbers
var c64 complex64 // float32 real and imaginary
var c128 complex128 // float64 real and imaginary
c := 3 + 4i // complex128 by default
Strings
Strings in Go are immutable sequences of bytes (usually UTF-8):
s := "Hello, World!"
// String length (bytes, not runes!)
len(s) // 13
// Accessing bytes
s[0] // 72 (byte value of 'H')
// Substring (slicing)
s[0:5] // "Hello"
s[:5] // "Hello"
s[7:] // "World!"
// Concatenation
greeting := "Hello" + ", " + "World!"
// Raw strings (no escape processing)
path := `C:\Users\name\file.txt`
multiline := `Line 1
Line 2
Line 3`
// Common string operations (from "strings" package)
import "strings"
strings.Contains(s, "World") // true
strings.HasPrefix(s, "Hello") // true
strings.HasSuffix(s, "!") // true
strings.ToUpper(s) // "HELLO, WORLD!"
strings.ToLower(s) // "hello, world!"
strings.Split("a,b,c", ",") // []string{"a", "b", "c"}
strings.Join([]string{"a","b"}, "-") // "a-b"
strings.TrimSpace(" hi ") // "hi"
strings.Replace(s, "World", "Go", 1) // "Hello, Go!"
Runes
A rune is an alias for int32 and represents a Unicode code point:
r := 'A' // rune (int32)
r2 := '世' // rune for Chinese character
// Iterating over strings by rune
s := "Hello, 世界"
for i, r := range s {
fmt.Printf("%d: %c\n", i, r)
}
// Converting string to runes
runes := []rune(s)
len(runes) // 9 (correct character count)
Booleans
var isTrue bool = true
var isFalse bool = false
// Boolean operators
a && b // AND
a || b // OR
!a // NOT
Type Conversions
Go requires explicit type conversions (no implicit casting):
var i int = 42
var f float64 = float64(i) // int to float64
var u uint = uint(i) // int to uint
// String conversions
import "strconv"
// Int to string
s := strconv.Itoa(42) // "42"
s := fmt.Sprintf("%d", 42) // "42"
// String to int
i, err := strconv.Atoi("42") // 42, nil
// Float to string
s := strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
// String to float
f, err := strconv.ParseFloat("3.14", 64) // 3.14, nil
// Bool to string
s := strconv.FormatBool(true) // "true"
// String to bool
b, err := strconv.ParseBool("true") // true, nil
Operators
Arithmetic Operators
a + b // Addition
a - b // Subtraction
a * b // Multiplication
a / b // Division
a % b // Modulus (remainder)
// Increment/Decrement (statements only, not expressions)
i++ // i = i + 1
i-- // i = i - 1
// Note: ++i and --i are NOT valid in Go
// Note: You cannot use i++ in an expression like x = i++
Comparison Operators
a == b // Equal
a != b // Not equal
a < b // Less than
a <= b // Less than or equal
a > b // Greater than
a >= b // Greater than or equal
Bitwise Operators
a & b // AND
a | b // OR
a ^ b // XOR
a &^ b // AND NOT (bit clear)
a << n // Left shift
a >> n // Right shift
Assignment Operators
a = b // Assign
a += b // a = a + b
a -= b // a = a - b
a *= b // a = a * b
a /= b // a = a / b
a %= b // a = a % b
a &= b // a = a & b
a |= b // a = a | b
a ^= b // a = a ^ b
a <<= n // a = a << n
a >>= n // a = a >> n
Pointers
Go has pointers but no pointer arithmetic:
// Declaring pointers
var p *int // Pointer to int, zero value is nil
i := 42
p = &i // & gets the address of a variable
// Dereferencing
fmt.Println(*p) // 42 (value at the address)
*p = 21 // Set value through pointer
fmt.Println(i) // 21
// Creating pointers with new()
p := new(int) // Allocates memory, returns *int
*p = 100
// Common pattern: pointer receivers
type Counter struct {
value int
}
func (c *Counter) Increment() {
c.value++ // Modifies the original struct
}
When to Use Pointers
- When you need to modify the original value
- When passing large structs (avoid copying)
- When a value might be nil (optional values)
// Function that modifies a value
func double(x *int) {
*x *= 2
}
num := 10
double(&num)
fmt.Println(num) // 20
Printing and Formatting
The fmt package provides formatted I/O:
import "fmt"
// Basic printing
fmt.Print("Hello") // No newline
fmt.Println("Hello") // With newline
fmt.Printf("Value: %d\n", 42) // Formatted
// Format verbs
%v // Default format
%+v // With field names (for structs)
%#v // Go syntax representation
%T // Type of the value
%% // Literal percent sign
%t // Boolean
%d // Integer (base 10)
%b // Integer (base 2)
%o // Integer (base 8)
%x, %X // Integer (base 16, lowercase/uppercase)
%f // Float (default precision)
%e, %E // Scientific notation
%.2f // Float with 2 decimal places
%s // String
%q // Quoted string
%c // Character (rune)
%p // Pointer
// Width and precision
%10d // Width 10, right-aligned
%-10d // Width 10, left-aligned
%010d // Width 10, zero-padded
%10.2f // Width 10, 2 decimal places
// Sprintf returns a string
s := fmt.Sprintf("Name: %s, Age: %d", "Alice", 30)
// Fprintf writes to any io.Writer
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
Input
import (
"bufio"
"fmt"
"os"
)
// Simple input with Scanf
var name string
var age int
fmt.Print("Enter name and age: ")
fmt.Scanf("%s %d", &name, &age)
// Reading a line with bufio
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter text: ")
text, _ := reader.ReadString('\n')
Comments
// Single-line comment
/*
Multi-line
comment
*/
// Documentation comments (go doc)
// Package math provides basic mathematical functions.
package math
// Add returns the sum of two integers.
func Add(a, b int) int {
return a + b
}
Next Steps
Continue to 03-control-flow.md to learn about if statements, loops, and switch.