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

  1. When you need to modify the original value
  2. When passing large structs (avoid copying)
  3. 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.