Go-Language Course
01hello
main.go
This is a basic Go program that prints "Hello, world!" to the console. Let's break it down step by step and refer to the relevant parts of the Go documentation for more details.
Package Declaration:
package main
Every Go program starts with a package declaration. Programs meant to be executable must use
package main
.
Importing Packages:
import "fmt"
The
import
statement is used to include the code from other packages. In this case, we're importing thefmt
package, which provides I/O functions.
Main Function:
func main() { fmt.Println("Hello, world!") }
The
main
function is the entry point of the program. It is called when the program starts.Within the
main
function,fmt.Println
is used to print the string "Hello, world!" to the console.
Detailed Explanation:
package main:
Defines the package name.
main
is a special package name that tells the Go compiler that this package will compile to an executable program.More about Packages.
import "fmt":
Imports the
fmt
package from the standard library, which contains functions for formatting I/O, like printing to the console.More about Imports.
func main():
Defines the
main
function, which is the entry point for the program. This function doesn't take any arguments or return any values.More about Functions.
fmt.Println("Hello, world!"):
- Calls the
Println
function from thefmt
package, which prints the specified string followed by a newline.
02variables
main.go
This Go program demonstrates the usage of variables, constants, and various data types. Let's break down the code and refer to the relevant parts of the Go documentation for more details.
Package Declaration:
package main
Importing Packages:
import "fmt"
Constants:
const LoginToken string = "ghabbhhjd" // Public
Constants are declared using the
const
keyword.LoginToken
is a string constant that is accessible throughout the package.Main Function:
func main() { // Variable Declarations var username string = "Arijit" fmt.Println(username) fmt.Printf("Variable is of type: %T \n", username) var isLoggedIn bool = false fmt.Println(isLoggedIn) fmt.Printf("Variable is of type: %T \n", isLoggedIn) var smallVal uint8 = 255 fmt.Println(smallVal) fmt.Printf("Variable is of type: %T \n", smallVal) var smallFloat float64 = 255.45544511254451885 fmt.Println(smallFloat) fmt.Printf("Variable is of type: %T \n", smallFloat) // Default values and some aliases var anotherVariable int fmt.Println(anotherVariable) fmt.Printf("Variable is of type: %T \n", anotherVariable) // Implicit type var website = "Prabhupadabooks.com" fmt.Println(website) // No var style numberOfUser := 300000.0 fmt.Println(numberOfUser) // Print the constant fmt.Println(LoginToken) fmt.Printf("Variable is of type: %T \n", LoginToken) }
Detailed Explanation:
Constant Declaration:
const LoginToken string = "ghabbhhjd"
: Declares a string constant namedLoginToken
. Constants are immutable.More about Constants.
Variable Declarations:
var username string = "Arijit"
: Declares a variableusername
of typestring
and initializes it with the value "Arijit".var isLoggedIn bool = false
: Declares a boolean variableisLoggedIn
and initializes it withfalse
.var smallVal uint8 = 255
: Declares an unsigned 8-bit integer variablesmallVal
and initializes it with255
.var smallFloat float64 = 255.45544511254451885
: Declares a 64-bit floating-point variablesmallFloat
and initializes it with a specific value.var anotherVariable int
: Declares an integer variableanotherVariable
without initializing it, so it defaults to0
.var website = "
Prabhupadabooks.com
"
: Uses implicit typing to declare a variablewebsite
with the type inferred from the assigned value.numberOfUser := 300000.0
: Uses the shorthand notation to declare and initialize a variablenumberOfUser
with the type inferred from the value.
Printing Variables:
fmt.Println(variable)
: Prints the value of the variable.fmt.Printf("Variable is of type: %T \n", variable)
: Prints the type of the variable.
03userinput
main.go
This Go program demonstrates user input, reading from the console, and basic error handling. Let's break down the code and refer to the relevant parts of the Go documentation for more details.
Package Declaration:
package main
Importing Packages:
import ( "bufio" "fmt" "os" )
The
import
statement is used to include multiple packages:bufio
,fmt
, andos
.Main Function:
func main() { welcome := "Welcome to user input" fmt.Println(welcome) reader := bufio.NewReader(os.Stdin) fmt.Println("Enter the rating for our Pizza:") // ReadString reads until the first occurrence of the delimiter '\n' input, _ := reader.ReadString('\n') fmt.Println("Thanks for rating,", input) fmt.Printf("Type of this rating is %T", input) }
Detailed Explanation:
Package Declaration and Imports:
package main
: Declares the package name.main
is used for executable programs.import ("bufio" "fmt" "os")
: Imports three packages:bufio
: Provides buffered I/O.fmt
: Implements formatted I/O functions.os
: Provides a platform-independent interface to operating system functionality, including standard input/output.
Variable Declaration and Initialization:
welcome := "Welcome to user input"
: Uses the shorthand notation to declare and initialize thewelcome
variable with a string.fmt.Println(welcome)
: Prints the welcome message.
Reading User Input:
reader := bufio.NewReader(os.Stdin)
: Creates a newbufio.Reader
that reads from the standard input (os.Stdin
).fmt.Println("Enter the rating for our Pizza:")
: Prompts the user to enter a rating.
Reading a Line of Input:
input, _ := reader.ReadString('\n')
: Reads a line of input from the user until the newline character ('\n'
) is encountered. The returned value is a string containing the input (including the newline character). The_
is used to ignore the error value returned byReadString
.fmt.Println("Thanks for rating,", input)
: Prints the user's rating.fmt.Printf("Type of this rating is %T", input)
: Prints the type of theinput
variable, which isstring
.
Additional Resources:
Effective Go: Effective Go - Errors
Go Blog: Error Handling and Go
Go Documentation: Go Error Package
04conversion
main.go
Sure, I'll streamline the documentation to focus on explaining the code without the instructions for running it.
Detailed Explanation
Package Declaration:
package main
Importing Packages:
import ( "bufio" "fmt" "os" "strconv" "strings" )
bufio
: Provides buffered I/O operations.fmt
: Implements formatted I/O.os
: Provides a platform-independent interface to operating system functionality.strconv
: Implements conversions to and from string representations of basic data types.strings
: Implements functions to manipulate string values.
Main Function:
func main() { fmt.Println("Welcome to our pizza app") fmt.Println("Please rate our pizza between 1 and 5") reader := bufio.NewReader(os.Stdin) input, _ := reader.ReadString('\n') fmt.Println("Thanks for rating,", input) numRating, err := strconv.ParseFloat(strings.TrimSpace(input), 64) if err != nil { fmt.Println("Error parsing rating:", err) } else { fmt.Println("Added 1 to your rating:", numRating+1) } }
Code Explanation
Greeting the User:
fmt.Println("Welcome to our pizza app") fmt.Println("Please rate our pizza between 1 and 5")
- Prints welcome messages to the console.
Reading User Input:
reader := bufio.NewReader(os.Stdin) input, _ := reader.ReadString('\n')
Creates a new buffered reader to read from standard input.
Reads a line of input from the user until a newline character is encountered. The
_
is used to ignore the error value returned byReadString
.
Acknowledging the User Input:
fmt.Println("Thanks for rating,", input)
- Prints the user-provided rating.
Converting String to Float:
numRating, err := strconv.ParseFloat(strings.TrimSpace(input), 64)
strings.TrimSpace(input)
: Removes any leading and trailing whitespace from the input string, including newline characters.strconv.ParseFloat(...)
: Converts the cleaned input string to afloat64
. If the conversion fails,err
will contain the error information.
Error Handling:
if err != nil { fmt.Println("Error parsing rating:", err) } else { fmt.Println("Added 1 to your rating:", numRating+1) }
Checks if an error occurred during the conversion. If so, prints the error message.
If no error occurred, adds
1
to the numerical rating and prints the result.
Additional Resources
String Conversion: strconv Package
String Manipulation: strings Package
Effective Go: Effective Go Guide
05mymaths
main.go
Here's a detailed explanation for the two Go programs dealing with mathematical operations, including type conversion, generating random numbers, and using cryptographic random numbers.
(a) Mathematical Operations and Basic Random Numbers
Package Declaration:
package main
Importing Packages:
import ( "fmt" "math/rand" "time" )
fmt
: Implements formatted I/O.math/rand
: Provides pseudorandom number generation.time
: Provides functionality for measuring and displaying time.
Main Function:
func main() { fmt.Println("Welcome to maths in golang") var mynumberOne int = 2 var mynumberTwo float64 = 4.5 fmt.Println("The sum is:", mynumberOne+int(mynumberTwo)) // Generating a random number rand.Seed(time.Now().UnixNano()) fmt.Println("Random number:", rand.Intn(5)+1) }
Code Explanation
Basic Arithmetic:
var mynumberOne int = 2 var mynumberTwo float64 = 4.5 fmt.Println("The sum is:", mynumberOne+int(mynumberTwo))
Declares two variables,
mynumberOne
(integer) andmynumberTwo
(float).Converts
mynumberTwo
to an integer before performing the addition to avoid type mismatch.
Generating a Random Number:
rand.Seed(time.Now().UnixNano()) fmt.Println("Random number:", rand.Intn(5)+1)
Seeds the random number generator with the current time to ensure different results in each run.
Generates a random integer between 1 and 5 using
rand.Intn(5)+1
.
Additional Resources
Random Numbers: math/rand Package
Time Package: time Package
(b) Cryptographic Random Numbers
Package Declaration:
package main
Importing Packages:
import ( "crypto/rand" "fmt" "math/big" )
crypto/rand
: Provides cryptographically secure random number generation.fmt
: Implements formatted I/O.math/big
: Implements arbitrary-precision arithmetic.
Main Function:
func main() { fmt.Println("Welcome to maths in golang") myRandomNum, _ := rand.Int(rand.Reader, big.NewInt(5)) fmt.Println("Cryptographic random number:", myRandomNum) }
Code Explanation
Generating a Cryptographic Random Number:
myRandomNum, _ := rand.Int(rand.Reader, big.NewInt(5)) fmt.Println("Cryptographic random number:", myRandomNum)
Uses
crypto/rand
to generate a cryptographically secure random number.rand.Int
reads fromrand.Reader
and generates a random number between 0 and 4 (sincebig.NewInt(5)
specifies the upper limit as 5).
Additional Resources
Cryptographic Random Numbers: crypto/rand Package
Big Integers: math/big Package
06mytime
main.go
Here's a breakdown of the Go program that demonstrates working with time in various ways, including obtaining the current time, formatting time strings, and creating custom time objects.
Code Explanation
Package Declaration:
package main
Importing Packages:
import ( "fmt" "time" )
fmt
: Implements formatted I/O.time
: Provides functionality for handling dates and times.
Main Function:
func main() { fmt.Println("Welcome to time study of golang") // Get the current time presentTime := time.Now() fmt.Println("Current time:", presentTime) // Format the current time fmt.Println("Formatted time:", presentTime.Format("01-02-2006 15:04:05 Monday")) // Create a custom date and time createdDate := time.Date(2020, time.August, 12, 23, 23, 0, 0, time.UTC) fmt.Println("Custom date and time:", createdDate) // Format the custom date fmt.Println("Formatted custom date:", createdDate.Format("01-02-2006 Monday")) }
Detailed Explanation
Obtaining Current Time:
presentTime := time.Now() fmt.Println("Current time:", presentTime)
time.Now
()
retrieves the current local time.presentTime
is of typetime.Time
, which represents the current time.
Formatting Time:
fmt.Println("Formatted time:", presentTime.Format("01-02-2006 15:04:05 Monday"))
presentTime.Format(layout string)
formats thepresentTime
according to the layout specified. The layout string"01-02-2006 15:04:05 Monday"
is a reference time used in Go to format dates. Each component (e.g.,01
for month,02
for day,2006
for year) must match the reference time to correctly format the date and time.
Creating Custom Date and Time:
createdDate := time.Date(2020, time.August, 12, 23, 23, 0, 0, time.UTC) fmt.Println("Custom date and time:", createdDate)
time.Date
(year int, month Month, day, hour, min, sec, nsec int, loc *Location)
creates a customtime.Time
object.time.August
andtime.UTC
are constants provided by thetime
package.
Formatting Custom Date and Time:
fmt.Println("Formatted custom date:", createdDate.Format("01-02-2006 Monday"))
createdDate.Format(layout string)
formats thecreatedDate
object similar to formatting the current time.
Output
When you run the program, it will output the current time, formatted current time, custom date and time, and formatted custom date as specified in the main
function.
Additional Resources
Time Package: time Package
Time Formatting: Time Formatting in Go
07mypointers
main.go
Here's an explanation of the two Go programs that illustrate the concept of pointers:
(a) Understanding Pointers Basics
Package Declaration:
package main
Importing Packages:
import "fmt"
fmt
: Implements formatted I/O.
Main Function:
func main() { fmt.Println("Welcome to a class on pointers") var ptr *int fmt.Println("Value of pointer is ", ptr) }
Code Explanation
Declaring a Pointer:
var ptr *int
ptr
is declared as a pointer to an integer (*int
). Pointers in Go are variables that store memory addresses.
Printing Pointer Value:
fmt.Println("Value of pointer is ", ptr)
- Since
ptr
is not initialized (nil
), it printsnil
.
- Since
Key Points
In Go, a pointer holds the memory address of a value.
If a pointer is declared without initialization, its zero value is
nil
, meaning it doesn't point to any valid memory address.
(b) Working with Pointers and Dereferencing
Package Declaration:
package main
Importing Packages:
import "fmt"
fmt
: Implements formatted I/O.
Main Function:
func main() { fmt.Println("Welcome to a class on pointers") myNumber := 23 var ptr = &myNumber fmt.Println("Value of actual pointer is ", ptr) fmt.Println("Value pointed to by pointer is ", *ptr) *ptr = *ptr + 2 fmt.Println("New value of myNumber is: ", myNumber) }
Code Explanation
Creating a Pointer:
var ptr = &myNumber
&myNumber
retrieves the memory address ofmyNumber
and assigns it toptr
.
Printing Pointer and Dereferencing:
fmt.Println("Value of actual pointer is ", ptr) fmt.Println("Value pointed to by pointer is ", *ptr)
*ptr
dereferences the pointer, retrieving the value stored at the memory addressptr
.
Modifying the Value through Pointer:
*ptr = *ptr + 2
- Modifies the value of
myNumber
indirectly through the pointer.
- Modifies the value of
Printing Updated Value:
fmt.Println("New value of myNumber is: ", myNumber)
- Prints the updated value of
myNumber
after modification via the pointer.
- Prints the updated value of
Key Points
Pointers in Go allow indirect access to variables and support more efficient passing of large data structures.
Dereferencing a pointer (
*ptr
) retrieves the value stored at the memory address pointed to byptr
.Modifying the value through a pointer affects the original variable.
08myarray
main.go
Here's an explanation of the Go program that demonstrates the use of arrays:
Understanding Arrays in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
fmt
: Implements formatted I/O.
Main Function:
func main() { fmt.Println("Welcome to arrays in Go") // Declaring and initializing an array of strings var fruitList [4]string fruitList[0] = "Apple" fruitList[1] = "Tomato" fruitList[3] = "Peach" fmt.Println("Fruit list is:", fruitList) fmt.Println("Length of fruit list is:", len(fruitList)) // Initializing an array of strings with specified values var vegList = [5]string{"potato", "beans", "mushroom"} fmt.Println("Veggie list is:", vegList) fmt.Println("Length of veggie list is:", len(vegList)) }
Code Explanation
Declaring and Initializing Arrays:
var fruitList [4]string
- Declares an array named
fruitList
that can hold 4 strings.
- Declares an array named
Assigning Values to Array Elements:
fruitList[0] = "Apple" fruitList[1] = "Tomato" fruitList[3] = "Peach"
- Assigns values to specific elements of the
fruitList
array. Note that array indexes in Go start at 0.
- Assigns values to specific elements of the
Printing Array and Array Length:
fmt.Println("Fruit list is:", fruitList) fmt.Println("Length of fruit list is:", len(fruitList))
- Prints the entire array
fruitList
and its length usinglen(fruitList)
.
- Prints the entire array
Initializing Arrays with Values:
var vegList = [5]string{"potato", "beans", "mushroom"}
- Initializes an array
vegList
of strings with 5 elements and assigns specific values during initialization.
- Initializes an array
Printing Initialized Array and Array Length:
fmt.Println("Veggie list is:", vegList) fmt.Println("Length of veggie list is:", len(vegList))
- Prints the entire array
vegList
and its length usinglen(vegList)
.
- Prints the entire array
Key Points
Arrays in Go have a fixed size and can store elements of the same type.
Elements of an array can be accessed using their index.
Arrays in Go are zero-indexed, meaning the first element is at index 0.
The length of an array can be obtained using the built-in function
len()
.
09myslices
main.go
(a) Basic Slice Operations
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("Welcome to video on slices") var fruitList = []string{"Apple", "Tomato", "Peach"} fmt.Printf("Type of fruitList is %T\n", fruitList) fruitList = append(fruitList, "Mango", "Banana") fmt.Println(fruitList) fruitList = append(fruitList[:3]) fmt.Println(fruitList) }
Code Explanation
Creating a Slice:
var fruitList = []string{"Apple", "Tomato", "Peach"}
- Creates a slice named
fruitList
with initial elements.
- Creates a slice named
Printing Slice Type:
fmt.Printf("Type of fruitList is %T\n", fruitList)
- Prints the type of
fruitList
, which is[]string
.
- Prints the type of
Appending to a Slice:
fruitList = append(fruitList, "Mango", "Banana") fmt.Println(fruitList)
- Appends elements to the slice.
Slicing a Slice:
fruitList = append(fruitList[:3]) fmt.Println(fruitList)
- Slices
fruitList
to keep only the first three elements.
- Slices
(b) Slice Manipulation and Sorting
Package Declaration:
package main
Importing Packages:
import ( "fmt" "sort" )
Main Function:
func main() { fmt.Println("Welcome to video on slices") highScores := make([]int, 4) highScores[0] = 234 highScores[1] = 945 highScores[2] = 465 highScores[3] = 867 highScores = append(highScores, 555, 666, 321) fmt.Println(highScores) fmt.Println(sort.IntsAreSorted(highScores)) sort.Ints(highScores) fmt.Println(highScores) }
Code Explanation
Creating a Slice with
make
:highScores := make([]int, 4)
- Creates a slice named
highScores
with a length of 4.
- Creates a slice named
Assigning Values to Slice Elements:
highScores[0] = 234 highScores[1] = 945 highScores[2] = 465 highScores[3] = 867
- Assigns values to specific elements in the
highScores
slice.
- Assigns values to specific elements in the
Appending to a Slice:
highScores = append(highScores, 555, 666, 321) fmt.Println(highScores)
- Appends additional elements to the slice.
Sorting a Slice:
fmt.Println(sort.IntsAreSorted(highScores)) sort.Ints(highScores) fmt.Println(highScores)
Checks if the slice is sorted using
sort.IntsAreSorted
.Sorts the slice using
sort.Ints
.
(c) Removing an Element from a Slice
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("Welcome to video on slices") // How to remove a value from slices based on index var courses = []string{"reactjs", "javascript", "swift", "python", "ruby"} fmt.Println(courses) var index int = 2 courses = append(courses[:index], courses[index+1:]...) fmt.Println(courses) }
Code Explanation
Creating a Slice:
var courses = []string{"reactjs", "javascript", "swift", "python", "ruby"} fmt.Println(courses)
- Creates a slice named
courses
with initial elements.
- Creates a slice named
Removing an Element from a Slice:
var index int = 2 courses = append(courses[:index], courses[index+1:]...) fmt.Println(courses)
- Removes the element at the specified index (2 in this case) by appending the elements before and after the index.
Key Points
Slices in Go are more flexible than arrays, allowing dynamic resizing.
Slices can be created using literals or the
make
function.Slices support various operations like appending, slicing, sorting, and removing elements.
10mymaps
main.go
Understanding Maps in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("Maps in golang") // Creating a map languages := make(map[string]string) // Adding key-value pairs to the map languages["JS"] = "JavaScript" languages["RB"] = "Ruby" languages["PY"] = "Python" // Printing the entire map fmt.Println("List of all languages:", languages) // Accessing a value by its key fmt.Println("JS stands for:", languages["JS"]) // Deleting a key-value pair from the map delete(languages, "RB") fmt.Println("List of all languages after deletion:", languages) // Iterating over the map using a loop for _, value := range languages { fmt.Printf("Language: %v\n", value) } }
Code Explanation
Creating a Map:
languages := make(map[string]string)
- Creates a map named
languages
with string keys and string values using themake
function.
- Creates a map named
Adding Key-Value Pairs to the Map:
languages["JS"] = "JavaScript" languages["RB"] = "Ruby" languages["PY"] = "Python"
- Adds key-value pairs to the
languages
map. For example, the key"JS"
is mapped to the value"JavaScript"
.
- Adds key-value pairs to the
Printing the Entire Map:
fmt.Println("List of all languages:", languages)
- Prints all key-value pairs in the
languages
map.
- Prints all key-value pairs in the
Accessing a Value by Its Key:
fmt.Println("JS stands for:", languages["JS"])
- Retrieves the value associated with the key
"JS"
and prints it.
- Retrieves the value associated with the key
Deleting a Key-Value Pair from the Map:
delete(languages, "RB") fmt.Println("List of all languages after deletion:", languages)
- Deletes the key-value pair with the key
"RB"
from thelanguages
map.
- Deletes the key-value pair with the key
Iterating Over the Map Using a Loop:
for _, value := range languages { fmt.Printf("Language: %v\n", value) }
- Iterates over the
languages
map, printing each value. The underscore (_
) is used to ignore the keys.
- Iterates over the
Key Points
Maps in Go are used to store key-value pairs and provide efficient lookups.
Maps can be created using the
make
function or map literals.You can add, access, and delete key-value pairs in a map.
Iterating over a map allows you to access both keys and values.
11mystructs
main.go
Understanding Structs in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Struct Definition:
type User struct { Name string Email string Status bool Age int }
Main Function:
func main() { fmt.Println("Structs in golang") // No inheritance in Go; No super or parent Arijit := User{"Arijit", "arijitdas.hashnode.dev", true, 19} fmt.Println(Arijit) fmt.Printf("Arijit details are: %+v\n", Arijit) fmt.Printf("Name is %v and email is %v.\n", Arijit.Name, Arijit.Email) }
Code Explanation
Defining a Struct:
type User struct { Name string Email string Status bool Age int }
- Defines a struct named
User
with four fields:Name
(string),Email
(string),Status
(bool), andAge
(int).
- Defines a struct named
Creating an Instance of a Struct:
Arijit := User{"Arijit", "arijitdas.hashnode.dev", true, 19}
- Creates an instance of the
User
struct with specific values for each field.
- Creates an instance of the
Printing the Struct:
fmt.Println(Arijit)
- Prints the struct instance
Arijit
.
- Prints the struct instance
Printing Struct Details with Field Names:
fmt.Printf("Arijit details are: %+v\n", Arijit)
- Prints the struct instance with field names and values using the
%+v
format specifier.
- Prints the struct instance with field names and values using the
Accessing and Printing Individual Fields:
fmt.Printf("Name is %v and email is %v.\n", Arijit.Name, Arijit.Email)
- Accesses and prints the
Name
andEmail
fields of theArijit
struct instance.
- Accesses and prints the
Key Points
Structs: Used to create custom data types in Go that group together different fields.
Instance Creation: Instances of structs can be created by specifying values for all fields.
Field Access: Fields of a struct instance can be accessed using the dot (
.
) operator.Printing Structs: Structs can be printed using
fmt.Println
andfmt.Printf
for detailed output.
12ifelse
main.go
Understanding if-else
Statements in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("If else in golang") loginCount := 10 var result string if loginCount < 10 { result = "Regular user" } else if loginCount > 10 { result = "Watch out" } else { result = "Exactly 10 login count" } fmt.Println(result) if 9%2 == 0 { fmt.Println("Number is even") } else { fmt.Println("Number is odd") } if num := 3; num < 10 { fmt.Println("Num is less than 10") } else { fmt.Println("Num is NOT less than 10") } // if err != nil { // Handle error // } }
Code Explanation
Using
if-else
for Simple Conditions:if loginCount < 10 { result = "Regular user" } else if loginCount > 10 { result = "Watch out" } else { result = "Exactly 10 login count" }
- Checks the value of
loginCount
and assigns a string toresult
based on the condition.
- Checks the value of
Printing the Result:
fmt.Println(result)
- Prints the
result
string based on theif-else
condition.
- Prints the
Checking for Even or Odd Number:
if 9%2 == 0 { fmt.Println("Number is even") } else { fmt.Println("Number is odd") }
- Checks if the number 9 is even or odd and prints the result.
Short Statement in
if
Condition:if num := 3; num < 10 { fmt.Println("Num is less than 10") } else { fmt.Println("Num is NOT less than 10") }
- Declares a variable
num
and checks if it is less than 10 within theif
statement.
- Declares a variable
Key Points
Conditional Statements: Used to execute different blocks of code based on conditions.
if-else
Structure: Allows for simple, compound, and nested conditions.Short Statements: Go allows short statements to be included in the
if
condition.
Explanation of the Commented Part
In the main
function, there is a commented section that reads:
// if err != nil {
// }
Code Explanation
Error Handling in Go:
In Go, it's common to handle errors using the pattern
if err != nil { ... }
.This pattern checks if an error has occurred and then executes a block of code to handle the error.
Context and Usage
Typical Error Handling Structure:
if err != nil { // Handle the error fmt.Println("An error occurred:", err) }
- This structure is used to check if a variable
err
(usually returned by a function) is notnil
. If it's notnil
, it means an error has occurred, and the error handling code inside theif
block will execute.
- This structure is used to check if a variable
Common Usage Example:
package main import ( "fmt" "os" ) func main() { file, err := os.Open("nonexistentfile.txt") if err != nil { fmt.Println("An error occurred:", err) return } defer file.Close() // Proceed with file operations }
- In this example, the
os.Open
function returns a file and an error. If the file does not exist,err
will be non-nil
, and the error message will be printed, and the function will return early.
- In this example, the
Key Points
Error Handling: In Go, error handling is done using the
if err != nil
pattern.Purpose: This pattern helps ensure that errors are caught and handled gracefully, preventing unexpected behavior or crashes.
Usage: Commonly used after function calls that return an error, such as file operations, network calls, or any function that might fail.
13switchcase
main.go
Understanding switch-case
Statements in Go
Package Declaration:
package main
Importing Packages:
import ( "fmt" "math/rand" "time" )
Main Function:
func main() { fmt.Println("Switch and case in golang") rand.Seed(time.Now().UnixNano()) diceNumber := rand.Intn(6) + 1 fmt.Println("Value of dice is ", diceNumber) switch diceNumber { case 1: fmt.Println("Dice value is 1 and you can open") case 2: fmt.Println("You can move 2 spots") case 3: fmt.Println("You can move to 3 spots") fallthrough case 4: fmt.Println("You can move to 4 spots") fallthrough case 5: fmt.Println("You can move to 5 spots") case 6: fmt.Println("You can move to 6 spots and roll dice again") default: fmt.Println("What was that!") } }
Code Explanation
Seeding the Random Number Generator:
rand.Seed(time.Now().UnixNano())
- Seeds the random number generator with the current time in nanoseconds to ensure different random numbers on each run.
Generating a Random Dice Number:
diceNumber := rand.Intn(6) + 1
- Generates a random number between 1 and 6 to simulate a dice roll.
Printing the Dice Value:
fmt.Println("Value of dice is ", diceNumber)
- Prints the generated dice value.
Switch-Case Statement:
switch diceNumber { case 1: fmt.Println("Dice value is 1 and you can open") case 2: fmt.Println("You can move 2 spots") case 3: fmt.Println("You can move to 3 spots") fallthrough case 4: fmt.Println("You can move to 4 spots") fallthrough case 5: fmt.Println("You can move to 5 spots") case 6: fmt.Println("You can move to 6 spots and roll dice again") default: fmt.Println("What was that!") }
Key Points
Switch-Case Statement: Used to select one of many code blocks to be executed.
case
: Each case compares the switch expression with the case value. If they match, the code block for that case is executed.fallthrough
: Allows execution to fall through to the next case. Without it, the switch statement will terminate after the matching case's code block is executed.
Example Cases:
case 1
: Prints "Dice value is 1 and you can open".case 2
: Prints "You can move 2 spots".case 3
: Prints "You can move to 3 spots" and falls through tocase 4
.case 4
: Prints "You can move to 4 spots" and falls through tocase 5
.case 5
: Prints "You can move to 5 spots".case 6
: Prints "You can move to 6 spots and roll dice again".
Default Case:
default
: Executes if no other case matches. Prints "What was that!".
14loops
main.go
Understanding Loops in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Loop Examples
(a) For Loop with Index
func main() {
fmt.Println("Welcome to loops in golang")
days := []string{"Sunday", "Tuesday", "Wednesday", "Friday", "Saturday"}
fmt.Println(days)
for d := 0; d < len(days); d++ {
fmt.Println(days[d])
}
}
Explanation:
for d := 0; d < len(days); d++
: Standardfor
loop with an index.Iterates over the
days
slice and prints each day.
(b) For Loop with Range
func main() {
fmt.Println("Welcome to loops in golang")
days := []string{"Sunday", "Tuesday", "Wednesday", "Friday", "Saturday"}
fmt.Println(days)
for i := range days {
fmt.Println(days[i])
}
}
Explanation:
for i := range days
: Usesrange
to iterate over the slice indices.Prints each day using the index
i
.
(c) For Loop with Range and Ignored Index
func main() {
fmt.Println("Welcome to loops in golang")
days := []string{"Sunday", "Tuesday", "Wednesday", "Friday", "Saturday"}
fmt.Println(days)
for _, day := range days {
fmt.Printf("index is and value is %v\n", day)
}
}
Explanation:
for _, day := range days
: Usesrange
to iterate over the slice values.The
_
ignores the index, andday
holds the value.Prints each day value directly.
(d) Loop with goto
and continue
func main() {
fmt.Println("Welcome to loops in golang")
rougueValue := 1
for rougueValue < 10 {
if rougueValue == 2 {
goto lco
}
if rougueValue == 5 {
rougueValue++
continue
}
fmt.Println("Value is: ", rougueValue)
rougueValue++
}
lco:
fmt.Println("Jumping at LearnCodeonline.in")
}
Explanation:
rougueValue := 1
: InitializesrougueValue
to 1.for rougueValue < 10
: Loops whilerougueValue
is less than 10.if rougueValue == 2 { goto lco }
: Usesgoto
to jump to the labellco
ifrougueValue
is 2.if rougueValue == 5 { rougueValue++; continue }
: Skips the rest of the loop and continues with the next iteration ifrougueValue
is 5.fmt.Println("Value is: ", rougueValue)
: Prints the value ofrougueValue
.rougueValue++
: IncrementsrougueValue
.lco:
: Label for thegoto
statement.fmt.Println("Jumping at
LearnCodeonline.in
")
: Executes when the loop jumps to thelco
label.
Key Points
For Loop: The only loop construct in Go, but it can be used in different ways.
Standard
for
Loop: Initializes, checks condition, and increments in one line.Range Loop: Iterates over elements in a slice, array, map, or string.
Infinite Loop:
for { ... }
runs indefinitely unless broken by a condition.
goto
Statement: Used to jump to a labeled statement within the same function. It's rarely used and should be avoided if possible for better readability.continue
Statement: Skips the current iteration of the loop and proceeds with the next iteration.
15functions
main.go
Understanding Functions in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("Welcome to functions in golang") greeter() result := adder(3, 5) fmt.Println("Result is: ", result) proRes, myMessage := proAdder(2, 5, 8, 7, 3) fmt.Println("Pro result is: ", proRes) fmt.Println("Pro Message is: ", myMessage) }
Explanation:
fmt.Println("Welcome to functions in golang")
: Prints a welcome message.greeter()
: Calls thegreeter
function to print "Namstey from golang".result := adder(3, 5)
: Calls theadder
function with arguments 3 and 5, stores the result inresult
, and prints it.proRes, myMessage := proAdder(2, 5, 8, 7, 3)
: Calls theproAdder
function with multiple arguments, assigns the returned values toproRes
andmyMessage
, and prints them.
Function Definitions:
adder
Function:func adder(valOne int, valTwo int) int { return valOne + valTwo }
Explanation:
func adder(valOne int, valTwo int) int
: Defines a function namedadder
that takes twoint
parameters (valOne
andvalTwo
) and returns their sum.
proAdder
Function:func proAdder(values ...int) (int, string) { total := 0 for _, val := range values { total += val } return total, "Hi Pro result function" }
Explanation:
func proAdder(values ...int) (int, string)
: Defines a variadic function namedproAdder
that accepts multipleint
values and returns their total sum (int
) and a fixed message (string
).
greeter
Function:func greeter() { fmt.Println("Namstey from golang") }
Explanation:
func greeter()
: Defines a function namedgreeter
that prints "Namstey from golang".
Key Points
Functions in Go:
Defined using
func
keyword followed by the function name, parameters (if any), return types (if any), and body enclosed in{}
.Can return multiple values.
Support variadic parameters using
...
.
Function Calls:
- Functions are called using their names followed by parentheses
()
with arguments (if any) passed inside.
- Functions are called using their names followed by parentheses
16methods
main.go
Understanding Methods in Go
Package Declaration:
package main
Importing Packages:
import "fmt"
Main Function:
func main() { fmt.Println("Structs in golang") Arijit := User{"Arijit", "Arijit@go.dev", true, 16} fmt.Println(Arijit) fmt.Printf("Arijit details are: %+v\n", Arijit) fmt.Printf("Name is %v and email is %v.\n", Arijit.Name, Arijit.Email) Arijit.GetStatus() Arijit.NewMail() fmt.Printf("Name is %v and email is %v.\n", Arijit.Name, Arijit.Email) }
Explanation:
Creates a
User
struct instanceArijit
with fieldsName
,Email
,Status
, andAge
.Prints details of
Arijit
.Calls methods
GetStatus()
andNewMail()
onArijit
.Prints updated
Name
andEmail
fields ofArijit
.
Struct Definition:
type User struct { Name string Email string Status bool Age int }
Explanation:
- Defines a
User
struct with fieldsName
,Email
,Status
, andAge
.
- Defines a
Method Definitions:
GetStatus()
Method:func (u User) GetStatus() { fmt.Println("Is user active: ", u.Status) }
Explanation:
Defines a method
GetStatus()
forUser
struct (u
).Prints the
Status
of the user.
NewMail()
Method:func (u User) NewMail() { u.Email = "test@go.dev" fmt.Println("Email of this user is: ", u.Email) }
Explanation:
Defines a method
NewMail()
forUser
struct (u
).Updates
Email
field of the user and prints the new email.
Key Points
Methods in Go:
Defined with a receiver, which can be a value (
User
) or a pointer (*User
).Allow struct types to have associated behavior.
Can modify struct fields, but modifications to value receivers are not propagated outside the method.
Receiver Type:
(u User)
indicates a value receiver, while(u *User)
would be a pointer receiver.Value receivers operate on a copy of the struct, whereas pointer receivers operate on the struct itself.
17defer
main.go
In this Go program, we are using defer
statements to schedule functions to be executed just before the surrounding function returns. Let's break down how defer
works in both the main
function and myDefer
function:
main
Function
func main() {
defer fmt.Println("World")
defer fmt.Println("One")
defer fmt.Println("Two")
fmt.Println("Hello")
myDefer()
}
Explanation:
defer fmt.Println("World")
,defer fmt.Println("One")
, anddefer fmt.Println("Two")
: Thesedefer
statements schedule thefmt.Println
functions to be executed in reverse order just beforemain
returns.fmt.Println("Hello")
: Prints "Hello" immediately.myDefer()
: Calls themyDefer
function.
When main
exits, the deferred functions execute in Last In, First Out (LIFO) order. Therefore, the output will be:
// world, One, Two
// 0, 1, 2, 3, 4
// hello, 43210, two, One, world
myDefer
Function
func myDefer() {
for i := 0; i < 5; i++ {
defer fmt.Print(i)
}
}
Explanation:
for i := 0; i < 5; i++
: Iterates from 0 to 4.defer fmt.Print(i)
: Defers the printing ofi
. Sincedefer
schedules the function call with the current value ofi
but delays its execution untilmyDefer
returns, the values ofi
are printed in reverse order during the function returns.
When myDefer
exits, the deferred functions execute in reverse order of their scheduling. Thus, the output will be:
43210
Key Points
defer
Statement:Schedules a function call to be executed when the surrounding function returns.
Multiple
defer
statements stack up and execute in LIFO order.Useful for cleanup actions, closing files, and releasing resources.
Behavior:
- Defer statements are evaluated immediately, but the actual function call is delayed until the surrounding function completes.
18files
main.go
This Go program demonstrates how to work with files, including creating, writing to, and reading from a file. Let's go through each part of the code:
Explanation of the Program
Package Declaration:
package main
Importing Packages:
import ( "fmt" "io" "io/ioutil" "os" )
fmt
: For formatted I/O.io
: For basic I/O operations.ioutil
: For reading files.os
: For operating system functionality like creating and opening files.
Main Function:
func main() { fmt.Println("Welcome to files in golang") content := "This needs to go in a file - LearnCodeOnline.in" file, err := os.Create("./mylcogofile.txt") checkNilErr(err) length, err := io.WriteString(file, content) checkNilErr(err) fmt.Println("length is: ", length) defer file.Close() readFile("./mylcogofile.txt") }
Explanation:
Prints a welcome message.
Creates a string
content
to be written to the file.Uses
os.Create
to create a new file namedmylcogofile.txt
and assigns it tofile
. If there's an error,checkNilErr
handles it.Writes
content
to the file usingio.WriteString
and checks for errors.Prints the length of the written content.
Defers the closing of the file until the surrounding function (
main
) returns.Calls
readFile
to read and print the content of the file.
Reading the File:
func readFile(filename string) { databyte, err := ioutil.ReadFile(filename) checkNilErr(err) fmt.Println("Text data inside the file is \n", string(databyte)) }
Explanation:
Reads the file specified by
filename
usingioutil.ReadFile
.Checks for errors.
Prints the content of the file as a string.
Error Checking Function:
func checkNilErr(err error) { if err != nil { panic(err) } }
Explanation:
Checks if the error is non-nil.
If there is an error, the function panics, which stops the normal execution of the program and prints an error message.
Key Points
File Creation and Writing:
os.Create
creates or truncates the named file. If the file already exists, it will be truncated.io.WriteString
writes the specified string to the file.
File Reading:
ioutil.ReadFile
reads the content of the file into memory. It's a simple and convenient way to read files, but not suitable for very large files due to memory constraints.
Error Handling:
- The
checkNilErr
function ensures that any errors encountered during file operations are properly handled, preventing the program from proceeding with an invalid state.
- The
Defer Statement:
defer file.Close()
ensures that the file is closed properly, even if an error occurs or the function returns early.
19webrequests
main.go
This Go program demonstrates how to make HTTP GET requests and handle the response. It includes fetching data from a URL, handling errors, and reading the response body. Let's go through the code step by step:
Explanation of the Program
Package Declaration:
package main
Importing Packages:
import ( "fmt" "io/ioutil" "net/http" )
fmt
: For formatted I/O.ioutil
: For reading the response body.net/http
: For making HTTP requests.
Constant Declaration:
const url = "https://lco.dev"
- Declares a constant
url
which holds the URL to be requested.
- Declares a constant
Main Function:
func main() { fmt.Println("LCO web request") response, err := http.Get(url) if err != nil { panic(err) } fmt.Printf("Response is of type: %T\n", response) defer response.Body.Close() // caller's responsibility to close the connection databytes, err := ioutil.ReadAll(response.Body) if err != nil { panic(err) } content := string(databytes) fmt.Println(content) }
Explanation:
Prints a message indicating that a web request is being made.
Makes an HTTP GET request to the specified
url
usinghttp.Get
. The response is stored inresponse
, and any error is handled by checkingerr
.If an error occurs,
panic(err)
stops the program and prints the error message.Prints the type of the
response
to show the type of object returned byhttp.Get
.defer response.Body.Close()
ensures that the response body is closed when the function completes, preventing resource leaks.Reads the response body using
ioutil.ReadAll
and stores it indatabytes
. Any errors are handled appropriately.Converts the response body from bytes to a string and prints the content.
Key Points
HTTP GET Request:
http.Get(url)
performs an HTTP GET request to the specified URL and returns the response and an error.
Response Handling:
The response is of type
*http.Response
, which contains the status code, headers, and body of the response.It is crucial to close the response body using
defer response.Body.Close()
to avoid resource leaks.
Reading the Response Body:
ioutil.ReadAll(response.Body)
reads the entire response body into memory. This is suitable for small to medium-sized responses but not ideal for very large responses due to memory constraints.
Error Handling:
- Proper error handling is demonstrated by checking
err
after making the request and reading the response body. Usingpanic(err)
for simplicity, though in production code, you might want to handle errors more gracefully.
- Proper error handling is demonstrated by checking
20urls
main.go
This example demonstrates how to handle and manipulate URLs using the net/url
package in Go. It covers parsing a URL, extracting different parts of it, and constructing a new URL.
Code Explanation
Package Declaration and Imports:
package main import ( "fmt" "net/url" )
Constant Declaration:
const myurl string = "https://lco.dev:3000/learn?coursename=reactjs&paymentid=ghbj456ghb"
Main Function:
func main() { fmt.Println("Welcome to handling URLs in golang") fmt.Println(myurl) // Parsing result, _ := url.Parse(myurl) fmt.Println(result.Scheme) fmt.Println(result.Host) fmt.Println(result.Path) fmt.Println(result.Port()) fmt.Println(result.RawQuery) qparams := result.Query() fmt.Printf("The type of query params are: %T\n", qparams) fmt.Println(qparams["coursename"]) for _, val := range qparams { fmt.Println("Param is: ", val) } partsOfUrl := &url.URL{ Scheme: "https", Host: "lco.dev", Path: "/tutcss", RawPath: "user=Arijit", } anotherURL := partsOfUrl.String() fmt.Println(anotherURL) }
Detailed Explanation
Printing the Original URL:
fmt.Println("Welcome to handling URLs in golang") fmt.Println(myurl)
Parsing the URL:
result, _ := url.Parse(myurl)
url.Parse(myurl)
parses the URL string and returns aURL
struct and an error. Here, the error is ignored using_
.
Extracting Parts of the URL:
fmt.Println(result.Scheme) // Prints "https" fmt.Println(result.Host) // Prints "lco.dev:3000" fmt.Println(result.Path) // Prints "/learn" fmt.Println(result.Port()) // Prints "3000" fmt.Println(result.RawQuery) // Prints "coursename=reactjs&paymentid=ghbj456ghb"
Handling Query Parameters:
qparams := result.Query() fmt.Printf("The type of query params are: %T\n", qparams) // Prints "url.Values" fmt.Println(qparams["coursename"]) // Prints "[reactjs]" for _, val := range qparams { fmt.Println("Param is: ", val) // Prints each parameter value }
result.Query()
returns a map of query parameters.
Constructing a New URL:
partsOfUrl := &url.URL{ Scheme: "https", Host: "lco.dev", Path: "/tutcss", RawPath: "user=Arijit", } anotherURL := partsOfUrl.String() fmt.Println(anotherURL) // Prints "https://lco.dev/tutcssuser=Arijit"
A new
URL
struct is created and populated with different parts.partsOfUrl.String()
converts the URL struct back to a string.
21webreqverbs
This example demonstrates how to perform different types of HTTP requests (GET, POST with JSON, and POST with form data) in Go using the net/http
package. It covers making requests, handling responses, and error handling.
Code Explanation
Package Declaration and Imports:
package main import ( "fmt" "io/ioutil" "net/http" "net/url" "strings" )
Main Function:
func main() { fmt.Println("Welcome to web verb video - LCO") PerformGetRequest() PerformPostJsonRequest() PerformPostFormRequest() }
- The
main
function calls different functions to demonstrate various types of HTTP requests.
- The
PerformGetRequest Function
func PerformGetRequest() {
const myurl = "http://localhost:8000/get"
response, err := http.Get(myurl)
if err != nil {
panic(err)
}
defer response.Body.Close()
fmt.Println("Status code: ", response.StatusCode)
fmt.Println("Content length is: ", response.ContentLength)
var responseString strings.Builder
content, _ := ioutil.ReadAll(response.Body)
byteCount, _ := responseString.Write(content)
fmt.Println("ByteCount is: ", byteCount)
fmt.Println(responseString.String())
}
Description: This function performs a GET request to the specified URL.
Steps:
Send GET Request: Use
http.Get
to send a GET request.Handle Error: If there is an error, the function panics.
Defer Closing: Defer closing the response body.
Print Status and Content Length: Print the status code and content length of the response.
Read and Print Response: Read the response body into a
strings.Builder
and print the response content.
PerformPostJsonRequest Function
func PerformPostJsonRequest() {
const myurl = "http://localhost:8000/post"
// fake JSON payload
requestBody := strings.NewReader(`
{
"coursename":"Let's go with golang",
"price": 0,
"platform":"learnCodeOnline.in"
}
`)
response, err := http.Post(myurl, "application/json", requestBody)
if err != nil {
panic(err)
}
defer response.Body.Close()
content, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(content))
}
Description: This function performs a POST request with a JSON payload.
Steps:
Create JSON Payload: Create a
strings.NewReader
with the JSON payload.Send POST Request: Use
http.Post
to send the POST request withapplication/json
content type.Handle Error: If there is an error, the function panics.
Defer Closing: Defer closing the response body.
Read and Print Response: Read the response body and print the response content.
PerformPostFormRequest Function
func PerformPostFormRequest() {
const myurl = "http://localhost:8000/postform"
// form data
data := url.Values{}
data.Add("firstname", "Arijit")
data.Add("lastname", "choudhary")
data.Add("email", "Arijit@go.dev")
response, err := http.PostForm(myurl, data)
if err != nil {
panic(err)
}
defer response.Body.Close()
content, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(content))
}
Description: This function performs a POST request with form data.
Steps:
Create Form Data: Create a
url.Values
and add form fields.Send POST Form Request: Use
http.PostForm
to send the POST request with the form data.Handle Error: If there is an error, the function panics.
Defer Closing: Defer closing the response body.
Read and Print Response: Read the response body and print the response content.
Key Points
HTTP GET Request:
Use
http.Get
to perform a GET request.Always defer closing the response body to ensure it is closed after reading.
Use
ioutil.ReadAll
to read the response body.
HTTP POST Request with JSON:
Use
http.Post
to perform a POST request with a JSON payload.Ensure the content type is set to
application/json
.
HTTP POST Request with Form Data:
Use
http.PostForm
to perform a POST request with form data.Create form data using
url.Values
and add form fields.
Error Handling:
Always check for and handle errors to avoid runtime panics.
Use
panic
for error handling in simple examples; consider more graceful error handling in production code.
Reading Response:
Use
ioutil.ReadAll
to read the response body.Convert the response body to a string and print it.
Note
For testing the POST requests, you can use Thunder Client (a VS Code extension) to send requests to http://localhost:8000/post
and http://localhost:8000/postform
. This allows you to simulate server responses and test the functionality of your code.
22bitmorejson
main.go
This example demonstrates how to encode (serialize) and decode (deserialize) JSON in Go using the encoding/json
package. It covers defining struct tags for JSON, encoding Go structs into JSON, and decoding JSON data into Go structs and maps.
Code Explanation
Package Declaration and Imports:
package main import ( "encoding/json" "fmt" )
Struct Definition:
type course struct { Name string `json:"coursename"` Price int Platform string `json:"website"` Password string `json:"-"` Tags []string `json:"tags,omitempty"` }
The
course
struct represents the structure of the data we will encode and decode.Struct tags (e.g.,
json:"coursename"
) specify the JSON key names.The
Password
field is omitted during JSON encoding due to thejson:"-"
tag.The
Tags
field is omitted if empty due to thejson:"tags,omitempty"
tag.
Main Function:
func main() { fmt.Println("Welcome to JSON video") // EncodeJson() DecodeJson() }
EncodeJson Function:
func EncodeJson() { lcoCourses := []course{ {"ReactJS Bootcamp", 299, "LearnCodeOnline.in", "abc123", []string{"web-dev", "js"}}, {"MERN Bootcamp", 199, "LearnCodeOnline.in", "bcd123", []string{"full-stack", "js"}}, {"Angular Bootcamp", 299, "LearnCodeOnline.in", "hit123", nil}, } // Package this data as JSON data finalJson, err := json.MarshalIndent(lcoCourses, "", "\t") if err != nil { panic(err) } fmt.Printf("%s\n", finalJson) }
EncodeJson
creates a slice ofcourse
structs and encodes it into a formatted JSON string usingjson.MarshalIndent
.The JSON output is printed to the console.
DecodeJson Function:
func DecodeJson() { jsonDataFromWeb := []byte(` { "coursename": "ReactJS Bootcamp", "Price": 299, "website": "LearnCodeOnline.in", "tags": ["web-dev","js"] } `) var lcoCourse course checkValid := json.Valid(jsonDataFromWeb) if checkValid { fmt.Println("JSON was valid") json.Unmarshal(jsonDataFromWeb, &lcoCourse) fmt.Printf("%#v\n", lcoCourse) } else { fmt.Println("JSON WAS NOT VALID") } // Some cases where you just want to add data to key value var myOnlineData map[string]interface{} json.Unmarshal(jsonDataFromWeb, &myOnlineData) fmt.Printf("%#v\n", myOnlineData) for k, v := range myOnlineData { fmt.Printf("Key is %v and value is %v and Type is: %T\n", k, v, v) } }
DecodeJson
validates and decodes JSON data from a byte slice into acourse
struct.It also demonstrates decoding JSON data into a
map[string]interface{}
for more flexible access to the data.The JSON validity is checked using
json.Valid
, and the data is unmarshalled usingjson.Unmarshal
.
Key Points
Struct Tags: Use struct tags to control JSON encoding and decoding, e.g.,
json:"key"
,json:"-"
, andjson:"omitempty"
.Encoding JSON: Convert Go structs to JSON using
json.Marshal
orjson.MarshalIndent
for pretty printing.Decoding JSON: Convert JSON data to Go structs or maps using
json.Unmarshal
.Validating JSON: Check if JSON data is valid using
json.Valid
.Handling Errors: Always check for and handle errors during JSON operations to avoid runtime panics.
Flexible Decoding: Use
map[string]interface{}
for flexible JSON decoding when the structure is not fixed.
This example illustrates the basic principles of working with JSON in Go, providing a foundation for more complex JSON handling scenarios.
23mymodules
This example demonstrates how to set up a simple web server in Go using the Gorilla Mux package, which provides powerful routing capabilities. We'll cover creating a module, setting up routing, and handling HTTP requests.
Code Explanation
Main Application:
- File:
main.go
- File:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
fmt.Println("Hello mod in golang")
greeter()
r := mux.NewRouter()
r.HandleFunc("/", serveHome).Methods("GET")
log.Fatal(http.ListenAndServe(":4000", r))
}
func greeter() {
fmt.Println("Hey there mod users")
}
func serveHome(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("<h1>Welcome to golang series on YT</h1>"))
}
Key Points
Modules:
Create a Go Module:
Run
go mod init <module-name>
in your project directory. This initializes a new module and creates ago.mod
file.Example:
go mod init mymodule
Dependencies:
Import Gorilla Mux:
Use
go get
to add the Gorilla Mux package to your project.Example:
go get github.com/gorilla/mux
Setting Up the Server:
Router Initialization:
- Initialize a new router using
mux.NewRouter()
.
- Initialize a new router using
Define Routes:
- Define routes using
r.HandleFunc()
. TheserveHome
function is set up to handle GET requests to the root path.
- Define routes using
Start Server:
- Start the server on port 4000 using
http.ListenAndServe(":4000", r)
. The server listens for incoming requests and handles them based on the defined routes.
- Start the server on port 4000 using
Handler Functions:
Greeter Function:
- A simple function to print a greeting message.
ServeHome Function:
- Handles the root path (
"/"
) and responds with an HTML message.
- Handles the root path (
Key Points Recap
Modules: Use
go mod init
to create a new module and manage dependencies.Routing: Gorilla Mux provides a powerful routing mechanism for building web applications.
Handlers: Define handler functions to manage different routes and HTTP methods.
Running the Code
Initialize the Module:
go mod init mymodule
Get Dependencies:
go get github.com/gorilla/mux
Run the Server:
go run main.go
(You can create the "vendor" by running "go mod vendor" in the terminal)
This setup forms the foundation for building more complex web applications in Go using modules and third-party packages like Gorilla Mux.
24buildapi
This example demonstrates how to build a simple RESTful API in Go using the Gorilla Mux package for routing. The API performs basic CRUD operations on a list of courses.
Code Explanation
Main Application:
- File:
main.go
- File:
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"strconv"
"time"
"github.com/gorilla/mux"
)
// Model for course - file
type Course struct {
CourseId string `json:"courseid"`
CourseName string `json:"coursename"`
CoursePrice int `json:"price"`
Author *Author `json:"author"`
}
type Author struct {
Fullname string `json:"fullname"`
Website string `json:"website"`
}
// fake DB
var courses []Course
// middleware, helper - file
func (c *Course) IsEmpty() bool {
// return c.CourseId == "" && c.CourseName == ""
return c.CourseName == ""
}
func main() {
fmt.Println("API - LearnCodeOnline.in")
r := mux.NewRouter()
//seeding
courses = append(courses, Course{CourseId: "2", CourseName: "ReactJS", CoursePrice: 299, Author: &Author{Fullname: "Arijit Das", Website: "lco.dev"}})
courses = append(courses, Course{CourseId: "4", CourseName: "MERN Stack", CoursePrice: 199, Author: &Author{Fullname: "Arijit Das", Website: "go.dev"}})
//routing
r.HandleFunc("/", serveHome).Methods("GET")
r.HandleFunc("/courses", getAllCourses).Methods("GET")
r.HandleFunc("/course/{id}", getOneCourse).Methods("GET")
r.HandleFunc("/course", createOneCourse).Methods("POST")
r.HandleFunc("/course/{id}", updateOneCourse).Methods("PUT")
r.HandleFunc("/course/{id}", deleteOneCourse).Methods("DELETE")
// listen to a port
log.Fatal(http.ListenAndServe(":4000", r))
}
//controllers - file
// serve home route
func serveHome(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("<h1>Welcome to API by LearnCodeOnline</h1>"))
}
func getAllCourses(w http.ResponseWriter, r *http.Request) {
fmt.Println("Get all courses")
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(courses)
}
func getOneCourse(w http.ResponseWriter, r *http.Request) {
fmt.Println("Get one course")
w.Header().Set("Content-Type", "application/json")
// grab id from request
params := mux.Vars(r)
// loop through courses, find matching id and return the response
for _, course := range courses {
if course.CourseId == params["id"] {
json.NewEncoder(w).Encode(course)
return
}
}
json.NewEncoder(w).Encode("No Course found with given id")
return
}
func createOneCourse(w http.ResponseWriter, r *http.Request) {
fmt.Println("Create one course")
w.Header().Set("Content-Type", "application/json")
// what if: body is empty
if r.Body == nil {
json.NewEncoder(w).Encode("Please send some data")
}
// what about - {}
var course Course
_ = json.NewDecoder(r.Body).Decode(&course)
if course.IsEmpty() {
json.NewEncoder(w).Encode("No data inside JSON")
return
}
//TODO: check only if title is duplicate
// loop, title matches with course.coursename, JSON
// generate unique id, string
// append course into courses
rand.Seed(time.Now().UnixNano())
course.CourseId = strconv.Itoa(rand.Intn(100))
courses = append(courses, course)
json.NewEncoder(w).Encode(course)
return
}
func updateOneCourse(w http.ResponseWriter, r *http.Request) {
fmt.Println("Update one course")
w.Header().Set("Content-Type", "application/json")
// first - grab id from req
params := mux.Vars(r)
// loop, id, remove, add with my ID
for index, course := range courses {
if course.CourseId == params["id"] {
courses = append(courses[:index], courses[index+1:]...)
var course Course
_ = json.NewDecoder(r.Body).Decode(&course)
course.CourseId = params["id"]
courses = append(courses, course)
json.NewEncoder(w).Encode(course)
return
}
}
//TODO: send a response when id is not found
}
func deleteOneCourse(w http.ResponseWriter, r *http.Request) {
fmt.Println("Delete one course")
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
//loop, id, remove (index, index+1)
for index, course := range courses {
if course.CourseId == params["id"] {
courses = append(courses[:index], courses[index+1:]...)
// TODO: send a confirm or deny response
break
}
}
}
Detailed Documentation
Main Application Setup:
Imports: Import necessary packages including
encoding/json
,fmt
,log
,math/rand
,net/http
,strconv
,time
, andgithub.com/gorilla/mux
.Struct Definitions:
Course
: Defines the structure of a course with fieldsCourseId
,CourseName
,CoursePrice
, andAuthor
.Author
: Defines the structure of an author with fieldsFullname
andWebsite
.
Fake Database:
var courses []Course
simulates a database.Middleware/Helper:
IsEmpty() bool
: Checks if a course'sCourseName
is empty.
Main Function:
Initializes the router.
Seeds the fake database with initial courses.
Sets up routing for various endpoints.
Starts the server on port 4000.
Controllers:
Serve Home Route:
func serveHome(w http.ResponseWriter, r *http.Request) { w.Write([]byte("<h1>Welcome to API by LearnCodeOnline</h1>")) }
- Serves a welcome message at the root path (
/
).
- Serves a welcome message at the root path (
Get All Courses:
func getAllCourses(w http.ResponseWriter, r *http.Request) { fmt.Println("Get all courses") w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(courses) }
- Responds with a list of all courses.
Get One Course:
func getOneCourse(w http.ResponseWriter, r *http.Request) { fmt.Println("Get one course") w.Header().Set("Content-Type", "application/json") // grab id from request params := mux.Vars(r) // loop through courses, find matching id and return the response for _, course := range courses { if course.CourseId == params["id"] { json.NewEncoder(w).Encode(course) return } } json.NewEncoder(w).Encode("No Course found with given id") return }
- Responds with a specific course based on the provided
id
.
- Responds with a specific course based on the provided
Create One Course:
func createOneCourse(w http.ResponseWriter, r *http.Request) { fmt.Println("Create one course") w.Header().Set("Content-Type", "application/json") // what if: body is empty if r.Body == nil { json.NewEncoder(w).Encode("Please send some data") } // what about - {} var course Course _ = json.NewDecoder(r.Body).Decode(&course) if course.IsEmpty() { json.NewEncoder(w).Encode("No data inside JSON") return } // generate unique id, string rand.Seed(time.Now().UnixNano()) course.CourseId = strconv.Itoa(rand.Intn(100)) courses = append(courses, course) json.NewEncoder(w).Encode(course) return }
- Creates a new course and adds it to the list of courses.
Update One Course:
func updateOneCourse(w http.ResponseWriter, r *http.Request) { fmt.Println("Update one course") w.Header().Set("Content-Type", "application/json") // first - grab id from req params := mux.Vars(r) // loop, id, remove, add with my ID for index, course := range courses { if course.CourseId == params["id"] { courses = append(courses[:index], courses[index+1:]...) var course Course _ = json.NewDecoder(r.Body).Decode(&
course) course.CourseId = params["id"] courses = append(courses, course) json.NewEncoder(w).Encode(course) return } } //TODO: send a response when id is not found } ``` - Updates an existing course based on the provided id
.
- Delete One Course: ```go func deleteOneCourse(w http.ResponseWriter, r *http.Request) { fmt.Println("Delete one course") w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
//loop, id, remove (index, index+1)
for index, course := range courses { if course.CourseId == params["id"] { courses = append(courses[:index], courses[index+1:]...) // TODO: send a confirm or deny response break } } } ``` - Deletes an existing course based on the provided id
.
Key Points Recap
Structs: Define the data models (
Course
andAuthor
).Routing: Use Gorilla Mux to handle various HTTP methods (GET, POST, PUT, DELETE).
Controllers: Implement handlers to manage the API endpoints.
Middleware: Implement helper functions to validate data.
Fake Database: Use a slice to simulate a database.
Running the Code
Initialize the Module:
go mod init mymodule
Get Dependencies:
go get github.com/gorilla/mux
Run the Server:
go run main.go
(type "go build ." in the terminal)
Access the API:
Use tools like Postman, Thunder Client, to interact with the API endpoints (
GET /courses
,POST /course
, etc.).Open a web browser and navigate to
http://localhost:4000/
to see the response from theserveHome
function.
25mongoapi
This application demonstrates how to create a RESTful API using Go and MongoDB. The API allows performing CRUD operations on a MongoDB collection named watchlist
. Here's a breakdown of each file and its role in the application.
1. controller/controller.go
This file handles the interaction with MongoDB and defines the API endpoint handlers.
Imports:
import ( "context" "encoding/json" "fmt" "log" "net/http" "github.com/ArijitDas2005/mongoapi/model" "github.com/gorilla/mux" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" )
context
: Provides context for database operations.encoding/json
: Handles JSON encoding and decoding.fmt
,log
,net/http
: Standard packages for formatting, logging, and HTTP handling.github.com/ArijitDas2005/mongoapi/model
: Importing themodel
package for theNetflix
struct.github.com/gorilla/mux
: Importing themux
package for routing.go.mongodb.org/mongo-driver/bson
,go.mongodb.org/mongo-driver/bson/primitive
,go.mongodb.org/mongo-driver/mongo
,go.mongodb.org/mongo-driver/mongo/options
: MongoDB driver packages for Go.
Global Variables:
const connectionString = "mongodb+srv://arijit:Hanuman@cluster0.jpewnn8.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0" const dbName = "netflix" const colName = "watchlist" var collection *mongo.Collection
connectionString
: MongoDB connection URI.dbName
: Name of the database.colName
: Name of the collection.collection
: MongoDB collection instance.
Init Function:
func init() { clientOption := options.Client().ApplyURI(connectionString) client, err := mongo.Connect(context.TODO(), clientOption) if err != nil { log.Fatal(err) } fmt.Println("MongoDB connection success") collection = client.Database(dbName).Collection(colName) fmt.Println("Collection instance is ready") }
Initializes the MongoDB client and connects to the database.
Assigns the collection instance to the global
collection
variable.
CRUD Operations:
Insert One Movie:
func insertOneMovie(movie model.Netflix) { inserted, err := collection.InsertOne(context.Background(), movie) if err != nil { log.Fatal(err) } fmt.Println("Inserted 1 movie in db with id: ", inserted.InsertedID) }
- Inserts a movie document into the MongoDB collection.
Update One Movie:
func updateOneMovie(movieId string) { id, _ := primitive.ObjectIDFromHex(movieId) filter := bson.M{"_id": id} update := bson.M{"$set": bson.M{"watched": true}} result, err := collection.UpdateOne(context.Background(), filter, update) if err != nil { log.Fatal(err) } fmt.Println("modified count: ", result.ModifiedCount) }
- Updates a movie document to set its
watched
field totrue
.
- Updates a movie document to set its
Delete One Movie:
func deleteOneMovie(movieId string) { id, _ := primitive.ObjectIDFromHex(movieId) filter := bson.M{"_id": id} deleteCount, err := collection.DeleteOne(context.Background(), filter) if err != nil { log.Fatal(err) } fmt.Println("Movie got deleted with delete count: ", deleteCount) }
- Deletes a movie document from the collection.
Delete All Movies:
func deleteAllMovie() int64 { deleteResult, err := collection.DeleteMany(context.Background(), bson.D{{}}, nil) if err != nil { log.Fatal(err) } fmt.Println("Number of movies deleted: ", deleteResult.DeletedCount) return deleteResult.DeletedCount }
- Deletes all documents from the collection.
Get All Movies:
func getAllMovies() []primitive.M { cur, err := collection.Find(context.Background(), bson.D{{}}) if err != nil { log.Fatal(err) } var movies []primitive.M for cur.Next(context.Background()) { var movie bson.M err := cur.Decode(&movie) if err != nil { log.Fatal(err) } movies = append(movies, movie) } defer cur.Close(context.Background()) return movies }
- Retrieves all movies from the collection.
API Handlers:
Get All Movies:
func GetMyAllMovies(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencode") allMovies := getAllMovies() json.NewEncoder(w).Encode(allMovies) }
Sets the content type to
application/x-www-form-urlencode
(likely intended to beapplication/json
).Retrieves and encodes all movies as JSON.
Create Movie:
func CreateMovie(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencode") w.Header().Set("Allow-Control-Allow-Methods", "POST") var movie model.Netflix _ = json.NewDecoder(r.Body).Decode(&movie) insertOneMovie(movie) json.NewEncoder(w).Encode(movie) }
- Decodes a movie from the request body and inserts it into the database.
Mark Movie as Watched:
func MarkAsWatched(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencode") w.Header().Set("Allow-Control-Allow-Methods", "PUT") params := mux.Vars(r) updateOneMovie(params["id"]) json.NewEncoder(w).Encode(params["id"]) }
- Marks a movie as watched by updating the
watched
field.
- Marks a movie as watched by updating the
Delete Movie:
func DeleteAMovie(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencode") w.Header().Set("Allow-Control-Allow-Methods", "DELETE") params := mux.Vars(r) deleteOneMovie(params["id"]) json.NewEncoder(w).Encode(params["id"]) }
- Deletes a movie document from the collection.
Delete All Movies:
func DeleteAllMovies(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/x-www-form-urlencode") w.Header().Set("Allow-Control-Allow-Methods", "DELETE") count := deleteAllMovie() json.NewEncoder(w).Encode(count) }
- Deletes all movie documents from the collection.
2. model/models.go
This file defines the data model used for MongoDB documents.
Model Definition:
package model import ( "go.mongodb.org/mongo-driver/bson/primitive" ) type Netflix struct { ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"` Movie string `json:"movie,omitempty"` Watched bool `json:"watched,omitempty"` }
Netflix
: Defines a struct for the movie document with fields for ID, movie name, and watched status.primitive.ObjectID
: Represents the MongoDB ObjectID for the document.
3. router/router.go
This file sets up the routes for the API.
Router Setup:
package router import ( "github.com/ArijitDas2005/mongoapi/controller" "github.com/gorilla/mux" ) func Router() *mux.Router { router := mux.NewRouter() router.HandleFunc("/api/movies", controller.GetMyAllMovies).Methods("GET") router.HandleFunc("/api/movie", controller.CreateMovie).Methods("POST") router.HandleFunc("/api/movie/{id}", controller.MarkAsWatched).Methods("PUT") router.HandleFunc("/api/movie/{id}", controller.DeleteAMovie).Methods("DELETE") router.HandleFunc("/api/deleteallmovie", controller.DeleteAllMovies).Methods("DELETE") return router }
Router() *mux.Router
: Creates and configures a new router with routes for the API endpoints.
4. main.go
This file starts the web server and listens for incoming requests.
Main Function:
package main import ( "fmt" "log" "net/http" "github.com/ArijitDas2005/mongoapi/router
" )
func main() { fmt.Println("MongoDB API") r := router.Router() fmt.Println("Server is getting started...") log.Fatal(http.ListenAndServe(":4000", r)) fmt.Println("Listening at port 4000 ...") } ``` - main()
: Entry point of the application. - Sets up the router and starts the server on port 4000, handling requests with the configured routes.
Summary
Controller: Contains logic for CRUD operations on the MongoDB collection and handlers for API endpoints.
Model: Defines the data structure for movie documents.
Router: Configures API routes and links them to handler functions.
Main: Starts the server and listens for incoming HTTP requests.
This structure separates concerns and follows best practices for organizing a Go-based web application using MongoDB.
26goroutines
Goroutines are a fundamental feature in Go that allows concurrent execution of functions. Below are two examples that demonstrate different aspects of using goroutines.
Example 1: Basic Goroutine Usage
package main
import (
"fmt"
"time"
)
func main() {
go greeter("Hello")
greeter("world")
}
func greeter(s string) {
for i := 0; i < 6; i++ {
time.Sleep(3 * time.Millisecond)
fmt.Println(s)
}
}
Explanation
Package and Imports:
package main import ( "fmt" "time" )
package main
: Defines the package asmain
, indicating this is an executable program.import "fmt"
: Imports thefmt
package for formatted I/O.import "time"
: Imports thetime
package for time-related functions.
main Function:
func main() { go greeter("Hello") greeter("world") }
func main()
: The entry point of the program.go greeter("Hello")
: Launches a new goroutine to execute thegreeter
function with the argument"Hello"
.greeter("world")
: Calls thegreeter
function directly, blocking the main goroutine until it completes.
greeter Function:
func greeter(s string) { for i := 0; i < 6; i++ { time.Sleep(3 * time.Millisecond) fmt.Println(s) } }
func greeter(s string)
: Defines a function that takes a strings
as an argument.for i := 0; i < 6; i++
: A loop that runs six times.time.Sleep(3 * time.Millisecond)
: Pauses the execution of the current goroutine for 3 milliseconds.fmt.Println(s)
: Prints the strings
to the console.
What Happens When We Run This
The
main
function starts a new goroutine withgreeter("Hello")
and then immediately callsgreeter("world")
.The
greeter("Hello")
function runs concurrently and prints "Hello" six times with a 3-millisecond pause between each print.The
greeter("world")
function runs in the main goroutine and prints "world" six times with a 3-millisecond pause between each print.Due to the concurrent execution, the output will interleave "Hello" and "world" in an unpredictable order.
Example 2: Goroutines with WaitGroup and Mutex
package main
import (
"fmt"
"net/http"
"sync"
)
var signals = []string{"test"}
var wg sync.WaitGroup //pointer
var mut sync.Mutex // pointer
func main() {
websitelist := []string{
"https://lco.dev",
"https://go.dev",
"https://google.com",
"https://fb.com",
"https://github.com",
}
for _, web := range websitelist {
go getStatusCode(web)
wg.Add(1)
}
wg.Wait()
fmt.Println(signals)
}
func getStatusCode(endpoint string) {
defer wg.Done()
res, err := http.Get(endpoint)
if err != nil {
fmt.Println("OOPS in endpoint")
} else {
mut.Lock()
signals = append(signals, endpoint)
mut.Unlock()
fmt.Printf("%d status code for %s\n", res.StatusCode, endpoint)
}
}
Explanation
Package and Imports:
package main import ( "fmt" "net/http" "sync" )
package main
: Defines the package asmain
, indicating this is an executable program.import "fmt"
: Imports thefmt
package for formatted I/O.import "net/http"
: Imports thenet/http
package for making HTTP requests.import "sync"
: Imports thesync
package for synchronization primitives such asWaitGroup
andMutex
.
Global Variables:
var signals = []string{"test"} var wg sync.WaitGroup //pointer var mut sync.Mutex // pointer
var signals = []string{"test"}
: Initializes a slice namedsignals
with a single element"test"
.var wg sync.WaitGroup
: Declares aWaitGroup
namedwg
to wait for goroutines to finish.var mut sync.Mutex
: Declares aMutex
namedmut
to synchronize access to shared resources.
main Function:
func main() { websitelist := []string{ "https://lco.dev", "https://go.dev", "https://google.com", "https://fb.com", "https://github.com", } for _, web := range websitelist { go getStatusCode(web) wg.Add(1) } wg.Wait() fmt.Println(signals) }
websitelist := []string{...}
: Initializes a slice of strings containing website URLs.for _, web := range websitelist { ... }
: Iterates over thewebsitelist
slice.go getStatusCode(web)
: Launches a new goroutine to execute thegetStatusCode
function with the current URL as an argument.wg.Add(1)
: Adds one to theWaitGroup
, indicating that there is one more goroutine to wait for.wg.Wait()
: Waits for all goroutines to finish. The program will not exit until allwg.Done()
calls are made.fmt.Println(signals)
: Prints the final state of thesignals
slice.
getStatusCode Function:
func getStatusCode(endpoint string) { defer wg.Done() res, err := http.Get(endpoint) if err != nil { fmt.Println("OOPS in endpoint") } else { mut.Lock() signals = append(signals, endpoint) mut.Unlock() fmt.Printf("%d status code for %s\n", res.StatusCode, endpoint) } }
func getStatusCode(endpoint string)
: Defines a function that takes a stringendpoint
as an argument.defer wg.Done()
: Ensures thatwg.Done()
is called when the function exits, decrementing theWaitGroup
counter by one.res, err := http.Get(endpoint)
: Makes an HTTP GET request to theendpoint
URL and stores the response inres
and any error inerr
.if err != nil { ... } else { ... }
: Checks if there was an error with the HTTP request.mut.Lock()
: Locks the mutex to ensure exclusive access to thesignals
slice.signals = append(signals, endpoint)
: Appends theendpoint
URL to thesignals
slice.mut.Unlock()
: Unlocks the mutex, allowing other goroutines to access thesignals
slice.fmt.Printf("%d status code for %s\n", res.StatusCode, endpoint)
: Prints the HTTP status code and theendpoint
URL.
What Happens When We Run This
The
main
function initializes a list of websites and starts a goroutine for each one to check its HTTP status code.Each goroutine makes an HTTP GET request to the specified URL and appends the URL to the
signals
slice if the request is successful.The
WaitGroup
ensures that themain
function waits for all goroutines to complete before printing the finalsignals
slice.The
Mutex
ensures that only one goroutine can access thesignals
slice at a time, preventing race conditions.
27mutexAndwaitGroups
This example demonstrates how to handle race conditions in Go using sync.WaitGroup
and sync.RWMutex
. Race conditions occur when multiple goroutines access shared resources concurrently, leading to unexpected behavior.
Code
package main
import (
"fmt"
"sync"
)
func main() {
fmt.Println("Race condition - LearnCodeonline.in")
wg := &sync.WaitGroup{}
mut := &sync.RWMutex{}
var score = []int{0}
wg.Add(3)
go func(wg *sync.WaitGroup, m *sync.RWMutex) {
fmt.Println("One R")
mut.Lock()
score = append(score, 1)
mut.Unlock()
wg.Done()
}(wg, mut)
go func(wg *sync.WaitGroup, m *sync.RWMutex) {
fmt.Println("Two R")
mut.Lock()
score = append(score, 2)
mut.Unlock()
wg.Done()
}(wg, mut)
go func(wg *sync.WaitGroup, m *sync.RWMutex) {
fmt.Println("Three R")
mut.Lock()
score = append(score, 3)
mut.Unlock()
wg.Done()
}(wg, mut)
go func(wg *sync.WaitGroup, m *sync.RWMutex) {
fmt.Println("Reading score")
mut.RLock()
fmt.Println(score)
mut.RUnlock()
wg.Done()
}(wg, mut)
wg.Wait()
fmt.Println(score)
}
Explanation
Package and Imports:
package main import ( "fmt" "sync" )
package main
: Defines the package name. In Go,main
indicates that this is an executable program.import
statement imports the necessary packages.fmt
is used for formatted I/O, andsync
provides synchronization primitives such asWaitGroup
andRWMutex
.
main Function:
func main() { fmt.Println("Race condition - LearnCodeonline.in") wg := &sync.WaitGroup{} mut := &sync.RWMutex{} var score = []int{0} wg.Add(3)
func main()
: The entry point of the program.fmt.Println("Race condition -
LearnCodeonline.in
")
: Prints a welcome message to the console.wg := &sync.WaitGroup{}
: Initializes aWaitGroup
to wait for the goroutines to finish their execution.mut := &sync.RWMutex{}
: Initializes a read-write mutex to synchronize access to the shared resource.var score = []int{0}
: Initializes a slice namedscore
with a single element0
.
Adding to WaitGroup:
wg.Add(3)
wg.Add(3)
: Adds three to theWaitGroup
, indicating that we have three goroutines to wait for.
First Goroutine:
go func(wg *sync.WaitGroup, m *sync.RWMutex) { fmt.Println("One R") mut.Lock() score = append(score, 1) mut.Unlock() wg.Done() }(wg, mut)
go func(wg *sync.WaitGroup, m *sync.RWMutex) { ... }(wg, mut)
: Launches a goroutine. This anonymous function locks the mutex, appends1
to thescore
slice, unlocks the mutex, and callswg.Done()
to indicate it has finished.mut.Lock()
: Locks the mutex to ensure exclusive access to thescore
slice.score = append(score, 1)
: Appends1
to thescore
slice.mut.Unlock()
: Unlocks the mutex, allowing other goroutines to access thescore
slice.wg.Done()
: Decrements theWaitGroup
counter by one.
Second Goroutine:
go func(wg *sync.WaitGroup, m *sync.RWMutex) { fmt.Println("Two R") mut.Lock() score = append(score, 2) mut.Unlock() wg.Done() }(wg, mut)
- Similar to the first goroutine, this one locks the mutex, appends
2
to thescore
slice, unlocks the mutex, and callswg.Done()
.
- Similar to the first goroutine, this one locks the mutex, appends
Third Goroutine:
go func(wg *sync.WaitGroup, m *sync.RWMutex) { fmt.Println("Three R") mut.Lock() score = append(score, 3) mut.Unlock() wg.Done() }(wg, mut)
- Similar to the previous goroutines, this one locks the mutex, appends
3
to thescore
slice, unlocks the mutex, and callswg.Done()
.
- Similar to the previous goroutines, this one locks the mutex, appends
Fourth Goroutine:
go func(wg *sync.WaitGroup, m *sync.RWMutex) { fmt.Println("Reading score") mut.RLock() fmt.Println(score) mut.RUnlock() wg.Done() }(wg, mut)
go func(wg *sync.WaitGroup, m *sync.RWMutex) { ... }(wg, mut)
: Launches a goroutine. This anonymous function reads thescore
slice and prints it.mut.RLock()
: Locks the mutex for reading, allowing concurrent read access.fmt.Println(score)
: Prints thescore
slice.mut.RUnlock()
: Unlocks the read lock, allowing other goroutines to access thescore
slice.wg.Done()
: Decrements theWaitGroup
counter by one.
Waiting for Goroutines:
wg.Wait() fmt.Println(score)
wg.Wait()
: Waits for all goroutines to finish. The program will not exit until allwg.Done()
calls are made.fmt.Println(score)
: Prints the final state of thescore
slice.
What Happens When We Run This
Print Message:
- The program starts by printing "Race condition - LearnCodeonline.in".
Goroutine Execution:
Four goroutines are launched. Three of them append values to the
score
slice while holding a write lock, and one reads thescore
slice while holding a read lock.The order of execution of these goroutines is not guaranteed and can vary.
Output:
The output will show the intermediate states and the final state of the
score
slice. The final state will contain the initial0
and the values appended by the goroutines.Sample output (order may vary):
Race condition - LearnCodeonline.in One R Two R Three R Reading score [0 1 2 3] [0 1 2 3]
Summary
This example illustrates the use of sync.WaitGroup
and sync.RWMutex
in Go to handle race conditions and synchronize access to shared resources. WaitGroup
ensures that the main function waits for all goroutines to complete before exiting, while RWMutex
provides mechanisms to lock the shared resource for reading and writing.
28channels
In this example, we explore the use of channels in Go. Channels provide a way for goroutines to communicate with each other and synchronize their execution.
Code
package main
import (
"fmt"
"sync"
)
func main() {
fmt.Println("Channels in golang- LearnCodeOnline.in")
myCh := make(chan int, 2)
wg := &sync.WaitGroup{}
// fmt.Println(<-myCh)
// myCh <- 5
wg.Add(2)
// R ONLY
go func(ch <-chan int, wg *sync.WaitGroup) {
val, isChanelOpen := <-myCh
fmt.Println(isChanelOpen)
fmt.Println(val)
//fmt.Println(<-myCh)
wg.Done()
}(myCh, wg)
// send ONLY
go func(ch chan<- int, wg *sync.WaitGroup) {
myCh <- 0
close(myCh)
// myCh <- 6
wg.Done()
}(myCh, wg)
wg.Wait()
}
Explanation
Package and Imports:
package main import ( "fmt" "sync" )
package main
: Defines the package name. In Go,main
indicates that this is an executable program.import
statement imports the necessary packages.fmt
is used for formatted I/O, andsync
provides synchronization primitives such asWaitGroup
.
main Function:
func main() { fmt.Println("Channels in golang- LearnCodeOnline.in")
func main()
: The entry point of the program.fmt.Println("Channels in golang-
LearnCodeOnline.in
")
: Prints a welcome message to the console.
Channel Creation:
myCh := make(chan int, 2) wg := &sync.WaitGroup{}
myCh := make(chan int, 2)
: Creates a buffered channelmyCh
that can hold up to 2 integers. Channels are used for communication between goroutines.wg := &sync.WaitGroup{}
: Initializes aWaitGroup
to wait for the goroutines to finish their execution.
Commented Code:
// fmt.Println(<-myCh) // myCh <- 5
- These lines are commented out and will not be executed. If uncommented, they would demonstrate receiving from and sending to the channel outside of a goroutine.
Adding to WaitGroup:
wg.Add(2)
wg.Add(2)
: Adds two to theWaitGroup
, indicating that we have two goroutines to wait for.
Receiving Goroutine:
go func(ch <-chan int, wg *sync.WaitGroup) { val, isChanelOpen := <-myCh fmt.Println(isChanelOpen) fmt.Println(val) //fmt.Println(<-myCh) wg.Done() }(myCh, wg)
go func(ch <-chan int, wg *sync.WaitGroup) { ... }(myCh, wg)
: Launches a goroutine. This anonymous function receives from themyCh
channel and takes aWaitGroup
pointer.val, isChanelOpen := <-myCh
: Receives a value frommyCh
.isChanelOpen
indicates if the channel is still open.fmt.Println(isChanelOpen)
: Prints whether the channel is open.fmt.Println(val)
: Prints the received value.//fmt.Println(<-myCh)
: A commented-out line that would receive another value from the channel if uncommented.wg.Done()
: Indicates that this goroutine has finished its execution.
Sending Goroutine:
go func(ch chan<- int, wg *sync.WaitGroup) { myCh <- 0 close(myCh) // myCh <- 6 wg.Done() }(myCh, wg)
go func(ch chan<- int, wg *sync.WaitGroup) { ... }(myCh, wg)
: Launches another goroutine. This anonymous function sends to themyCh
channel and takes aWaitGroup
pointer.myCh <- 0
: Sends the integer0
to the channel.close(myCh)
: Closes the channel, signaling that no more values will be sent on this channel.// myCh <- 6
: A commented-out line that would send another value to the channel if uncommented. This would cause a panic because the channel is closed.wg.Done()
: Indicates that this goroutine has finished its execution.
Waiting for Goroutines:
wg.Wait()
wg.Wait()
: Waits for both goroutines to finish. The program will not exit until bothwg.Done()
calls are made.
What Happens When We Run This
Print Message:
- The program starts by printing "Channels in golang- LearnCodeOnline.in".
Channel Operations:
Two goroutines are launched: one for receiving and one for sending.
The sending goroutine sends
0
to the channel and then closes it.The receiving goroutine receives the value
0
from the channel and prints it, along with the status of the channel (which will betrue
for open andfalse
for closed).
Output:
The output will be:
Channels in golang- LearnCodeOnline.in true 0
Channel Closure:
After receiving the value, the channel is closed, and both goroutines signal that they are done.
The main function waits for both goroutines to finish and then exits.
Summary
This example illustrates the use of channels and goroutines in Go to perform concurrent programming. Channels provide a mechanism for safe communication between goroutines, and sync.WaitGroup
ensures that the main function waits for all goroutines to complete before exiting.
Subscribe to my newsletter
Read articles from Arijit Das directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by