In this quick guide, we’ll journey through the fundamentals of Go variables with practical examples, enabling you to harness their power effectively.
1.Declaring Variables: In Go, variables can be explicitly and implicitly declared using walrus operator (:=) declared. We can also have “Compound Creation”, “Block Creation”.
Most important thing here is you must use declared variables. Compiler will throw error for unused variables.
package main
import "fmt"
func main() {
//implicit declaration
name := "John Doe"
//explicit declaration
var age int
age = 30
// compound creation
var a, b, c = 1, 2, "compound"
// block creation
var (
d int = 3
e int = 4
f = "block"
)
// compound can also be done using walrus operator
g, h, i := 5, 6, "walrus compound"
fmt.Println("Name:", name)
fmt.Println("Age:", age)
fmt.Printf("Print compound : %v %v %v \n", a, b, c)
fmt.Printf("Print block : %v %v %v \n", d, e, f)
fmt.Printf("Print walrus compound : %v %v %v \n", g, h, i)
}
2.Immutable and Mutable Variables: Go supports both immutable and. mutable variables. Immutable variables are declared using the ‘const’ keyword, while mutable variables are declared using ‘var’.
package main
import "fmt"
func main() {
const pi = 3.14 // immutable
var radius = 5 // mutable
fmt.Println("Area:", pi*float64(radius*radius))
}
3.Scope and Lifetime: Variables in Go have different scopes — package-level, function-level, or block-level.
package main
import "fmt"
var globalVar = 100 // package-level variable
func main() {
var localVar = 50 // function-level variable
{
var blockVar = 10 // block-level variable
fmt.Println("Block variable:", blockVar)
}
fmt.Println("Local variable:", localVar)
fmt.Println("Global variable:", globalVar)
}
Explanation:
globalVar
is a package-level variable, declared outside any function. It can be accessed from any file within the same package.localVar
is a function-level variable, declared within themain
function. It is only accessible within themain
function and cannot be accessed from outside.blockVar
is a block-level variable, declared within a block enclosed by curly braces{}
inside themain
function. It is only accessible within that block and cannot be accessed from outside or from within themain
function.
4.Concurrency and Goroutines: Variables in Goroutines can be shared among concurrent processes, requiring synchronization to maintain data integrity.
package main
import (
"fmt"
"sync"
)
var counter = 0
func incrementCounter(wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 1000; i++ {
counter++
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go incrementCounter(&wg)
go incrementCounter(&wg)
wg.Wait()
fmt.Println("Counter:", counter)
}
Explanation:
- The
counter
variable is declared globally to be accessed and modified by multiple Goroutines. - The
incrementCounter
function is defined to increment thecounter
in a loop for 1000 iterations. It receives a pointer to async.WaitGroup
as an argument. Thedefer wg.Done()
statement ensures thatwg.Done()
is called when the function exits, effectively decrementing the WaitGroup counter once the function completes its execution. - In the
main
function, async.WaitGroup
namedwg
is created to synchronize the Goroutines. It's incremented by 2 usingwg.Add(2)
to indicate that there are two Goroutines that need to be waited for. - Two Goroutines are launched concurrently using the
go
keyword, each executing theincrementCounter
function with a pointer to thewg
WaitGroup. wg.Wait()
blocks until the WaitGroup counter becomes 0, indicating that both Goroutines have completed their execution.- Finally, the value of the
counter
variable is printed, showing the total number of increments performed by both Goroutines.
5.Pointers and How to use them: A pointer is a variable that stores the memory address of another variable. It allows indirect access to the value of the variable it points to. Understanding pointers is crucial for efficient memory management and passing references to data structures in functions. Let’s delve into pointers with an example:
package main
import "fmt"
func main() {
// Declare a variable
var num int = 42
// Declare a pointer variable
var ptr *int
// Assign the address of 'num' to 'ptr'
ptr = &num
// Accessing the value using the pointer
fmt.Println("Value of num:", num)
fmt.Println("Address of num:", &num)
fmt.Println("Value of num via pointer:", *ptr)
fmt.Println("Address stored in pointer:", ptr)
// Modifying the value using the pointer
*ptr = 100
fmt.Println("Modified value of num via pointer:", num)
}
Explanation:
- We declare a variable
num
of typeint
and assign it the value42
. - We declare a pointer variable
ptr
of type*int
. The asterisk*
denotes thatptr
is a pointer. - We assign the address of the
num
variable to the pointerptr
using the&
operator. This operation is called "taking the address of" or "referencing". - We print the value of
num
, the address ofnum
, the value ofnum
accessed via the pointer (*ptr
), and the address stored in the pointer. - We modify the value of
num
indirectly through the pointer by assigning100
to*ptr
. This operation is called "dereferencing".
Conclusion: With these practical examples, you’ve embarked on a journey through the essence of Go variables. Whether you’re building simple scripts or complex applications, mastering variables is essential for crafting robust and efficient Go programs. Keep exploring, keep coding, and let the power of Go variables drive your innovations forward!