Go is a statically typed language. Variables must have a type, either explicitly specified or inferred by the compiler.
1. Variables
A variable is a named storage location in memory that holds a value.
Declaring Variables
In Go, you can declare variables in several ways:
A) Using the var
Keyword
package main
import "fmt"
func main() {
var name string = "Alice"
var age int = 25
var height float64 = 5.8
fmt.Println(name, age, height)
}
var name string = "Alice"
→ Explicitly declares a variablename
of typestring
.var age int = 25
→ Declaresage
as anint
.var height float64 = 5.8
→ Declaresheight
as afloat64
.
B) Type Inference (Omitting Type)
Go allows type inference, meaning it automatically determines the type based on the assigned value.
package main
import (
"fmt"
"reflect"
)func main() {
var city = "Hyd" // Go infers city as a string
var population = 80_00000_0 // there can be underscore in the middle of value
fmt.Println(city, population)
fmt.Println(reflect.TypeOf(city), reflect.TypeOf(population))
}
reflect.TypeOf() is used to know the type of the variable
C) Short Variable Declaration (:=
)
Inside functions, you can use the shorthand declaration (:=
), which is equivalent to var
but more concise.
package main
import (
"fmt"
"reflect"
)func main() {
name := "Alice"
age := 25
fmt.Println(name, age)
fmt.Println(reflect.TypeOf(name), reflect.TypeOf(age))
}
💡 Note: The :=
shorthand can only be used inside functions, get erros if used for global variables:
D) Multiple Variable Declaration
You can declare multiple variables at once:
package main
import (
"fmt"
"reflect"
)func main() {
var x, y, z int = 1, 2, 3
a, b, c := "hello", 10, true
fmt.Println(x, y, z, a, b, c)
fmt.Println(reflect.TypeOf(a), reflect.TypeOf(c))
}
E) Zero Values (Default Initialization)
If you declare a variable without initializing it, Go assigns a default “zero value.”
package main
import (
"fmt"
"reflect"
)func main() {
var num int // Defaults to 0
var str string // Defaults to "" (empty string)
var flag bool // Defaults to false
fmt.Println(num, str, flag)
fmt.Println(reflect.TypeOf(num), reflect.TypeOf(flag))
}
2. Constants
A constant is a variable whose value cannot be changed after declaration.
Declaring Constants
Use the const
keyword:
package main
import (
"fmt"
"reflect"
)func main() {
const pi float64 = 3.1415
const appName = "MyGoApp"
fmt.Println(pi, appName)
fmt.Println(reflect.TypeOf(pi), reflect.TypeOf(appName))
}
pi
is a constant of typefloat64
.appName
is a constant of typestring
.
Constants vs. Variables
constants and variables are both used to store data, but they have some key differences:
package main
import (
"fmt"
"reflect"
)func main() {
var age = 25
name := "Alice"
age = 26 // Changing the value of age
const pi = 3.14
const greeting = "Hello, World!"
// pi = 3.14159 // This would cause an error:
//cannot assign to pi (neither addressable nor a map index expression)
fmt.Println(age, name, pi, greeting)
fmt.Println(reflect.TypeOf(age), reflect.TypeOf(pi))
}
Variables
- Mutable: The value of a variable can change during the execution of a program.
- Declaration: In Go, you declare a variable using the
var
keyword or the shorthand:=
.
Constants
- Immutable: Once a constant is assigned a value, it cannot be changed.
- Declaration: In Go, you declare a constant using the
const
keyword.
Variables can be updated, while constants cannot. Use variables when you need to store data that might change. Use constants for fixed values that should not change throughout the program, such as mathematical constants or configuration values.
3. Constants with iota
(Auto-Incrementing Values)
Go provides iota
, which automatically generates incremental integer values.
package main
import (
"fmt"
"reflect"
)func main() {
const (
A = iota // 0
B // 1
C // 2
)
fmt.Println(A, B, C) // expected output 0,1,2
fmt.Println(reflect.TypeOf(A), reflect.TypeOf(C))
}
💡 Tip: iota
is useful for defining enumerations.
4. Constants with Expressions
Constants can be initialized using expressions.
package main
import (
"fmt"
"reflect"
)
func main() {
const x = 5 * 2 // Allowed
var y = x * 2 // Allowed
const z = y * 2 // ❌ ERROR (constants can't use non-constant values)
fmt.Println(x, y, z) // expected output 0,1,2
fmt.Println(reflect.TypeOf(x), reflect.TypeOf(z))
}
Example Program
package main
import "fmt"
func main() {
var name string = "Alice"
age := 30
const country = "USA"
fmt.Println("Name:", name)
fmt.Println("Age:", age)
fmt.Println("Country:", country)
// Uncommenting the line below will cause an error
// country = "Canada" // ❌ ERROR: Cannot change a constant
//cannot assign to country (neither addressable nor a map index expression)
}
Variables in Detail
A) Variable Scope: Global vs. Local
In Go, variables can be declared at the package level (global) or inside functions (local).
💡 Global variables are accessible across functions within the same package.
package main
import "fmt"
var globalVar = "I am global" // Accessible throughout the package
func main() {
localVar := "I am local"
fmt.Println(localVar) // ✅ Allowed
if true {
blockVar := "I exist only inside this block"
fmt.Println(blockVar) // ✅ Allowed
}
fmt.Println(globalVar) // ✅ Allowed
// fmt.Println(blockVar) // ❌ ERROR: blockVar is out of scope:
//undefined: blockVar
}
💡 Local variables exist only within their function or block.
B) Shadowing in Go
If a local variable has the same name as a global one, it shadows the global variable.
package main
import "fmt"
var message = "Global Message"
func main() {
message := "Local Message"
fmt.Println(message) // Output: Local Message (shadows global)
}
💡 Go will use the closest-scoped variable when resolving names.
C) Pointers and Variables
A pointer holds the memory address of a variable.
package main
import "fmt"
func main() {
x := 10
p := &x // `p` stores the memory address of `x`
fmt.Println("Value of x:", x) // 10
fmt.Println("Address of x:", p) // Some memory address
fmt.Println("Value at p:", *p) // 10 (dereferencing)
}
💡 Pointers are useful when passing large data structures efficiently.
2. Constants in Detail
A) Typed vs. Untyped Constants
Constants in Go can be typed or untyped.An untyped constant can be assigned to different types.
💡 Typed constants have a fixed type, while untyped constants adapt to their usage.
B) Constant Expressions
Constants support arithmetic operations.
💡 Expressions in constants must involve only constants.
D) iota
with Bitwise Operations
iota simplifies sequential values. iota
is useful for bit-masking.
package main
import (
"fmt"
"reflect"
)
func main() {
const typedInt int = 42 // Explicit type
const untypedInt = 42 // No type (flexible)
fmt.Println(typedInt, untypedInt)
fmt.Println(reflect.TypeOf(typedInt), reflect.TypeOf(untypedInt))
var x float64 = untypedInt // ✅ Allowed
fmt.Println(x, untypedInt)
fmt.Println(reflect.TypeOf(x), reflect.TypeOf(untypedInt))
const a = 10
const b = 20
const sum = a + b // Allowed
fmt.Println(a, b, sum)
fmt.Println(reflect.TypeOf(a), reflect.TypeOf(sum))
const (
Read = 1 << iota // 1 (0001)
Write // 2 (0010)
Execute // 4 (0100)
)
fmt.Println(Read, Write, Execute)
fmt.Println(reflect.TypeOf(Read), reflect.TypeOf(Execute))
p := &x // `p` stores the memory address of `x`
fmt.Println("Value of x:", x) // 10
fmt.Println("Address of x:", p) // Some memory address
fmt.Println("Value at p:", *p) // 10 (dereferencing)
}
💡 This is useful for defining permissions or flags.
3. Common Mistakes & Gotchas
A) Forgetting Variable Initialization
var x int
fmt.Println(x) // Output: 0 (default zero value)
💡 Always initialize variables when needed.
B) Misusing :=
Outside Functions
package main
var x := 10 // ❌ ERROR: := cannot be used at package level
💡 Use var
instead of :=
outside functions.