Variable Declaration and Type Inference
Go supports short variable declaration using the := operaotr, which automatically infers the data type based on the assigned value.
package main
import "fmt"
func main() {
username := "Alice"
fmt.Println(username)
}
Output:
Alice
Formatted Output with Printf
The fmt.Printf function allows for formatted printing. Common verbs include %T for type, %d for integers, and %p for memory addresses.
package main
import "fmt"
func main() {
user := "Bob"
age := 30
fmt.Println(user, age)
// Print types
fmt.Printf("%T,%T\n", user, age)
}
Output:
Bob 30
string,int
Memory addresses remain consistent even when the variable value changes.
package main
import "fmt"
func main() {
score := 100
fmt.Printf("Value: %d, Address: %p\n", score, &score)
score = 200
fmt.Printf("Value: %d, Address: %p\n", score, &score)
}
Swapping Values
Go allows simultaneous assignment, making variable swapping concise without a temporary variable.
package main
import "fmt"
func main() {
x, y := 5, 10
fmt.Println(x, y)
x, y = y, x
fmt.Println(x, y)
}
Output:
5 10
10 5
Anonymous Variables
When a function returns multiple values but only some are needed, the underscore _ acts as an anonymous variable to discard unwanted results.
package main
import "fmt"
func getStatus() (int, string) {
return 200, "OK"
}
func main() {
// Only capture the status code
code, _ := getStatus()
fmt.Println(code)
}
Variable Scope
Global variables must be declared using var. Local variables can shadow global variables within their scope.
package main
import "fmt"
var message = "Global Scope"
func show() {
fmt.Println(message)
}
func main() {
show()
// Local shadowing
message := "Local Scope"
fmt.Println(message)
}
Output:
Global Scope
Local Scope
Constants and Iota
Constants are defined using const. The iota keyword acts as an auto-incrementing counter within a constant block, resetting at each new const declaration.
package main
import "fmt"
func main() {
const (
a = iota // 0
b // 1
c = "text"
d // "text"
e = 10
f // 10
g = iota // 7 (index in block)
)
fmt.Println(a, b, c, d, e, f, g)
}
Basic Data Types
Boolean types default to false. Numeric types default to 0.
package main
import "fmt"
func main() {
var isActive bool
var count int = 50
var price float64 = 19.99
fmt.Printf("Type: %T, Value: %t\n", isActive, isActive)
fmt.Printf("Type: %T, Value: %d\n", count, count)
fmt.Printf("Type: %T, Value: %.1f\n", price, price)
}
Characters and Runes
Single quotes denote a rune (int32), while double quotes denote a string.
package main
import "fmt"
func main() {
var char rune = 'A'
var text string = "A"
fmt.Printf("Rune Value: %d\n", char)
fmt.Printf("String Value: %s\n", text)
}
Type Conversion
Go requires explicit type conversion; implicit casting is not supported.
package main
import "fmt"
func main() {
whole := 10
decimal := 10.5
// Explicit conversion
f := float64(whole)
i := int(decimal)
fmt.Printf("%T\n", f)
fmt.Printf("%T\n", i)
}
Operators and Input
Increment operators like ++ are statements, not expressions, so they cannot be used inside fmt.Println.
package main
import "fmt"
func main() {
val := 10
val++
fmt.Println(val) // Valid
// fmt.Println(val++) // Invalid
}
Reading user input can be done using fmt.Scanln.
package main
import "fmt"
func main() {
var input int
fmt.Println("Enter a number:")
fmt.Scanln(&input)
fmt.Println("Received:", input)
}
Switch Statements
Switch cases can include multiple conditions. The fallthrough keyword allows execution to continue into the next case.
package main
import "fmt"
func main() {
grade := 85
switch {
case grade >= 90:
fmt.Println("A")
case grade >= 80:
fmt.Println("B")
fallthrough
case grade >= 70:
fmt.Println("C")
default:
fmt.Println("F")
}
}
String Handling
The len function returns the byte length, which may differ from character count for multi-byte Unicode characters. Iterating with range yields runes.
package main
import "fmt"
func main() {
text := "Hello 世界"
fmt.Println("Byte Len:", len(text))
for index, char := range text {
fmt.Printf("Index: %d, Char: %c\n", index, char)
}
}
Functions and Closures
Functions are first-class types. Closures allow inner functions to capture variables from the outer scope.
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next()) // 1
fmt.Println(next()) // 2
}
Deferred Execution
The defer keyword schedules a function call to run after the surrounding function completes. Deferred calls are executed in LIFO order.
package main
import "fmt"
func main() {
defer fmt.Println("First")
defer fmt.Println("Second")
fmt.Println("Immediate")
}
Output:
Immediate
Second
First
Arrays and Slices
Arrays are value types, while slices are reference types pointing to underlying arrays.
package main
import "fmt"
func modifySlice(s []int) {
s[0] = 99
}
func main() {
data := []int{1, 2, 3}
modifySlice(data)
fmt.Println(data) // [99 2 3]
}
Slices can be expanded using append. If capacity is exceeded, a new underlying array is allocated.
package main
import "fmt"
func main() {
s := []int{1, 2}
s = append(s, 3, 4)
fmt.Println(s)
}
Error Handling
Go uses explicit error returns. panic stops execution, while recover inside a deferred function can regain control.
package main
import (
"errors"
"fmt"
)
func safeDivide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
func main() {
res, err := safeDivide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(res)
}
}
Time Package
The standard library provides robust time handling capabilities.
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("Year:", now.Year())
fmt.Println("Weekday:", now.Weekday())
}