Packages & Import packages
- package is a namespace that groups related Go files together.
- by convention, package name is the last directory name where the sources are stored eg-import “math/rand” , rand is the directory name where the sources are stored and will have package rand for all sources.
- directory which stores all related go source files
/*
mathutils/
add.go
subtract.go
*/
package mathutils // Both uses mathutils lib- Single Import package, multiple packages import, alias imports & blank imports
import "fmt" // Single Import
// Multiple Imports
import (
"fmt"
"math"
)
// Alias Imports
import m "math"
import (
f "fmt"
m "math"
)
// Blank Imports => forces to run init() of the package, but don't want to use its symbols.
import _ "net/http/pprof"- Special package main -> Entry point to the application. And must have main() method as the entry point to the application.
- main() function takes no arguments and returns nothing.
- Package can have automatic initialisation function, which runs before main()
func init() {
fmt.Println("Package initialized")
}
// Order of execution
/*
imported packages init()
↓
current package init()
↓
main()
*/- Package visibility is handled with identifiers which starts with capital case i.e
- Name -> Visible outside the package
- name -> Only visible inside the package
Modules
- Creating new Module
go mod init github.com/user/project - Importing module
import "github.com/user/project/mathutils"
Functions
- A function in Go is a reusable block of code that performs a specific task.
- Parameter vs Arguments
Term Meaning Parameters Variables defined in function signature Arguments Actual values passed to the function
// Decleration practices
func functionName(parameters) returnType {
// function body
}
// Decleration & calling
func add(a int, b int) int { // parameters
return a + b
}
result := add(3, 5) // arguments- Types Grouping & Multiple returns
func add(a, b int) int {
return a + b
}
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
q, err := divide(10, 3) // Multiple Return, Mainly used in error handling- Named return in functions.
func rectangle(l, w int) (area int) {
area = l * w
return
}- Variadic functions accept variable number of arguments.
func sum(nums ...int) int {
total := 0
for _, v := range nums {
total += v
}
return total
}
// Usage
sum(1,2,3)
sum(10,20,30,40)
nums := []int{1,2,3}
sum(nums...)- Functions are first-class citizens (can be assigned to variables & passed).
- Annonymouns functions & lambdas
go func() {
fmt.Println("hello")
}()- closure is a function that captures variables from its surrounding scope.
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// Usage
c := counter()
fmt.Println(c()) // 1
fmt.Println(c()) // 2- Pass by value
func modify(x int) {
x = 10
}
a := 5
modify(a)
fmt.Println(a) // still 5- Pass by reference (still pass by value, but the value which is passed is a pointer to the original varaible)
func modify(x *int) {
*x = 10
}
a := 5
modify(&a)
fmt.Println(a) // 10- Struct methods -
r Rectangleis called a receiver (value receiver). & pointer receiver (helps avoid copying a large struct)
type Rectangle struct {
width int
height int
}
func (r Rectangle) Area() int { // value reciever
return r.width * r.height
}
func (r *Rectangle) Scale(factor int) { // pointer reciever
r.width *= factor
}- defer function call is heavily used for locks, safe file closing etc. This uses LIFO ordering of stack. executed when surrounding method is completed.
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
/*
3
2
1
*/Datatypes & Variables
- Basic usage
var age int = 25 // Type explicity specified
age := 25 // Type implicity inferred (short hand decleration), ONLY functions scope (NOT in global scope).- Type implicitly inferred, can only be used within the functions. It cannot be used in global scope.
- Primitive types
// Whole Numbers
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
// Floating Numbers
float32
float64
//Boolean true/false
bool
// String - immutable sequence of bytes
string
/*
- immutable
- UTF-8 encoded
- concatenation using `+`
*/- Composite Types
// Arrays => Fixed size, cannot be changed once its already declated & initialized.
var nums [3]int = [3]int{1,2,3}
// Slices => Dynamic size, automatically resized
nums := []int{1,2,3}
/*
- pointer to array
- length
- capacity
*/
// Maps => key-value pairs
ages := map[string]int{
"John": 25,
"Anna": 30,
}
value := ages["John"] // fetching values
age, ok := ages["John"] // checking if value exists
// Struct
type User struct {
Name string
Age int
}
u := User{
Name: "John",
Age: 25
}-
Default values
Type Default value int 0 float 0.0 bool false string "" slice nil map nil pointer nil struct zero values for all fields
var age int
fmt.Println(age) // 0- Constants
- Constants MUST be known at compile time. Otherwise the compiler will panic.
- Generally numbers, strings, booleans or expressions made from those are good candidates for constants.
- Hence, maps, slices, struct and arrays CANNOT be constants. these are runtime data structures & involves memory allocation at runtime.
const pi float64 = 3.14159- Multiple declerations, variable shadowing,
var a, b int = 1, 2
var (
name string = "John"
age int = 30
)
// Shadowing
x := 10
if true {
x := 20
fmt.Println(x) // 20
}
fmt.Println(x) // 10- nil values
- pointers
- slices
- maps
- channels
- interfaces
- functions
- Iota - auto increment values (Similar to enum)
const (
Sunday = iota
Monday
Tuesday
)
Sunday // value 0- Type aliases
type Age int
var myAge Age = 25- Blank Identifier for return values
value, _ := someFunction() - Type conversion / Type casting
var a int = 10
var b float64 = float64(a)- Type conversions between string & primitive types
import "strconv"
var intString string = "42"
var i, err = strconv.Atoi(intString)
var number int = 12
var s string = strconv.Itoa(number)Comments
- Comments should explain why, NOT just what
- Single-Line Comments - Used for short explanations.
// This is a single-line comment
x := 10- Multi-Line Comments - Used for longer explanations or temporarily disabling code.
/*
This is a
multi-line comment
*/- Documentation Comments (Important) - Go uses comments to generate documentation automatically.
- Documentation comments:
- start with the name of the thing being described
- end with a period
// Add returns the sum of two integers.
func Add(a, b int) int {
return a + b
}- Package Comments - Every package should have a package-level comment.
- Placed before the package declaration.
// Package mathutils provides basic math helper functions.
package mathutils