Go-Language Course

Arijit DasArijit Das
59 min read

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.

  1. Package Declaration:

     package main
    
    • Every Go program starts with a package declaration. Programs meant to be executable must use package main.

    • Package Documentation

  2. Importing Packages:

     import "fmt"
    
    • The import statement is used to include the code from other packages. In this case, we're importing the fmt package, which provides I/O functions.

    • Import Declarations

  3. 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.

    • Function Declarations

    • fmt package

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 the fmt 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.

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. Constants:

     const LoginToken string = "ghabbhhjd" // Public
    

    Constants are declared using the const keyword. LoginToken is a string constant that is accessible throughout the package.

  4. 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 named LoginToken. Constants are immutable.

  • More about Constants.

Variable Declarations:

  • var username string = "Arijit": Declares a variable username of type string and initializes it with the value "Arijit".

  • var isLoggedIn bool = false: Declares a boolean variable isLoggedIn and initializes it with false.

  • var smallVal uint8 = 255: Declares an unsigned 8-bit integer variable smallVal and initializes it with 255.

  • var smallFloat float64 = 255.45544511254451885: Declares a 64-bit floating-point variable smallFloat and initializes it with a specific value.

  • var anotherVariable int: Declares an integer variable anotherVariable without initializing it, so it defaults to 0.

  • var website = "Prabhupadabooks.com": Uses implicit typing to declare a variable website with the type inferred from the assigned value.

  • numberOfUser := 300000.0: Uses the shorthand notation to declare and initialize a variable numberOfUser 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.

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import (
         "bufio"
         "fmt"
         "os"
     )
    

    The import statement is used to include multiple packages: bufio, fmt, and os.

  3. 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 the welcome variable with a string.

  • fmt.Println(welcome): Prints the welcome message.

Reading User Input:

  • reader := bufio.NewReader(os.Stdin): Creates a new bufio.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 by ReadString.

  • fmt.Println("Thanks for rating,", input): Prints the user's rating.

  • fmt.Printf("Type of this rating is %T", input): Prints the type of the input variable, which is string.

Additional Resources:

04conversion

main.go

Sure, I'll streamline the documentation to focus on explaining the code without the instructions for running it.

Detailed Explanation

  1. Package Declaration:

     package main
    
  2. 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.

  3. 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 by ReadString.

  • 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 a float64. 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

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

  1. Package Declaration:

     package main
    
  2. 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.

  3. 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) and mynumberTwo (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

(b) Cryptographic Random Numbers

  1. Package Declaration:

     package main
    
  2. 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.

  3. 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 from rand.Reader and generates a random number between 0 and 4 (since big.NewInt(5) specifies the upper limit as 5).

Additional Resources

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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import (
         "fmt"
         "time"
     )
    
    • fmt: Implements formatted I/O.

    • time: Provides functionality for handling dates and times.

  3. 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 type time.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 the presentTime 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 custom time.Time object.

    • time.August and time.UTC are constants provided by the time package.

  • Formatting Custom Date and Time:

      fmt.Println("Formatted custom date:", createdDate.Format("01-02-2006 Monday"))
    
    • createdDate.Format(layout string) formats the createdDate 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

07mypointers

main.go

Here's an explanation of the two Go programs that illustrate the concept of pointers:

(a) Understanding Pointers Basics

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
    • fmt: Implements formatted I/O.
  3. 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 prints nil.

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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
    • fmt: Implements formatted I/O.
  3. 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 of myNumber and assigns it to ptr.
  • 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 address ptr.
  • Modifying the Value through Pointer:

      *ptr = *ptr + 2
    
    • Modifies the value of myNumber indirectly through the pointer.
  • Printing Updated Value:

      fmt.Println("New value of myNumber is: ", myNumber)
    
    • Prints the updated value of myNumber after modification via the pointer.

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 by ptr.

  • 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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
    • fmt: Implements formatted I/O.
  3. 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.
  • 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.
  • 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 using len(fruitList).
  • 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.
  • 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 using len(vegList).

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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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.
  • Printing Slice Type:

      fmt.Printf("Type of fruitList is %T\n", fruitList)
    
    • Prints the type of fruitList, which is []string.
  • 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.

(b) Slice Manipulation and Sorting

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import (
         "fmt"
         "sort"
     )
    
  3. 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 withmake:

      highScores := make([]int, 4)
    
    • Creates a slice named highScores with a length of 4.
  • 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.
  • 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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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.
  • 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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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 the make function.
  • 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".
  • Printing the Entire Map:

      fmt.Println("List of all languages:", languages)
    
    • Prints all key-value pairs in the languages map.
  • Accessing a Value by Its Key:

      fmt.Println("JS stands for:", languages["JS"])
    
    • Retrieves the value associated with the key "JS" and prints it.
  • 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 the languages map.
  • 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.

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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. Struct Definition:

     type User struct {
         Name   string
         Email  string
         Status bool
         Age    int
     }
    
  4. 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), and Age (int).
  • 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.
  • Printing the Struct:

      fmt.Println(Arijit)
    
    • Prints the struct instance Arijit.
  • 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.
  • Accessing and Printing Individual Fields:

      fmt.Printf("Name is %v and email is %v.\n", Arijit.Name, Arijit.Email)
    
    • Accesses and prints the Name and Email fields of the Arijit struct instance.

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 and fmt.Printf for detailed output.

12ifelse

main.go

Understanding if-else Statements in Go

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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

  • Usingif-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 to result based on the condition.
  • Printing the Result:

      fmt.Println(result)
    
    • Prints the result string based on the if-else condition.
  • 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 inif 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 the if statement.

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 not nil. If it's not nil, it means an error has occurred, and the error handling code inside the if block will execute.
  • 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.

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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import (
         "fmt"
         "math/rand"
         "time"
     )
    
  3. 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 to case 4.

    • case 4: Prints "You can move to 4 spots" and falls through to case 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

  1. Package Declaration:

     package main
    
  2. 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++: Standard for 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: Uses range 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: Uses range to iterate over the slice values.

    • The _ ignores the index, and day 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: Initializes rougueValue to 1.

    • for rougueValue < 10: Loops while rougueValue is less than 10.

    • if rougueValue == 2 { goto lco }: Uses goto to jump to the label lco if rougueValue is 2.

    • if rougueValue == 5 { rougueValue++; continue }: Skips the rest of the loop and continues with the next iteration if rougueValue is 5.

    • fmt.Println("Value is: ", rougueValue): Prints the value of rougueValue.

    • rougueValue++: Increments rougueValue.

    • lco:: Label for the goto statement.

    • fmt.Println("Jumping atLearnCodeonline.in"): Executes when the loop jumps to the lco label.

Key Points

  • For Loop: The only loop construct in Go, but it can be used in different ways.

    • Standardfor 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

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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 the greeter function to print "Namstey from golang".

      • result := adder(3, 5): Calls the adder function with arguments 3 and 5, stores the result in result, and prints it.

      • proRes, myMessage := proAdder(2, 5, 8, 7, 3): Calls the proAdder function with multiple arguments, assigns the returned values to proRes and myMessage, and prints them.

  4. 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 named adder that takes two int parameters (valOne and valTwo) 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 named proAdder that accepts multiple int 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 named greeter 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.

16methods

main.go

Understanding Methods in Go

  1. Package Declaration:

     package main
    
  2. Importing Packages:

     import "fmt"
    
  3. 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 instance Arijit with fields Name, Email, Status, and Age.

      • Prints details of Arijit.

      • Calls methods GetStatus() and NewMail() on Arijit.

      • Prints updated Name and Email fields of Arijit.

  4. Struct Definition:

     type User struct {
         Name   string
         Email  string
         Status bool
         Age    int
     }
    
    • Explanation:

      • Defines a User struct with fields Name, Email, Status, and Age.
  5. Method Definitions:

    • GetStatus() Method:

        func (u User) GetStatus() {
            fmt.Println("Is user active: ", u.Status)
        }
      
      • Explanation:

        • Defines a method GetStatus() for User 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() for User 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"), and defer fmt.Println("Two"): These defer statements schedule the fmt.Println functions to be executed in reverse order just before main returns.

    • fmt.Println("Hello"): Prints "Hello" immediately.

    • myDefer(): Calls the myDefer 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 of i. Since defer schedules the function call with the current value of i but delays its execution until myDefer returns, the values of i 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

  1. Package Declaration:

     package main
    
  2. 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.

  3. 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 named mylcogofile.txt and assigns it to file. If there's an error, checkNilErr handles it.

      • Writes content to the file using io.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.

  4. 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 using ioutil.ReadFile.

      • Checks for errors.

      • Prints the content of the file as a string.

  5. 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.
  • 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

  1. Package Declaration:

     package main
    
  2. 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.

  3. Constant Declaration:

     const url = "https://lco.dev"
    
    • Declares a constant url which holds the URL to be requested.
  4. 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 using http.Get. The response is stored in response, and any error is handled by checking err.

      • 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 by http.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 in databytes. 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. Using panic(err) for simplicity, though in production code, you might want to handle errors more gracefully.

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

  1. Package Declaration and Imports:

     package main
    
     import (
         "fmt"
         "net/url"
     )
    
  2. Constant Declaration:

     const myurl string = "https://lco.dev:3000/learn?coursename=reactjs&paymentid=ghbj456ghb"
    
  3. 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

  1. Printing the Original URL:

     fmt.Println("Welcome to handling URLs in golang")
     fmt.Println(myurl)
    
  2. Parsing the URL:

     result, _ := url.Parse(myurl)
    
    • url.Parse(myurl) parses the URL string and returns a URL struct and an error. Here, the error is ignored using _.
  3. 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"
    
  4. 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.
  5. 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

  1. Package Declaration and Imports:

     package main
    
     import (
         "fmt"
         "io/ioutil"
         "net/http"
         "net/url"
         "strings"
     )
    
  2. 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.

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:

    1. Send GET Request: Use http.Get to send a GET request.

    2. Handle Error: If there is an error, the function panics.

    3. Defer Closing: Defer closing the response body.

    4. Print Status and Content Length: Print the status code and content length of the response.

    5. 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:

    1. Create JSON Payload: Create a strings.NewReader with the JSON payload.

    2. Send POST Request: Use http.Post to send the POST request with application/json content type.

    3. Handle Error: If there is an error, the function panics.

    4. Defer Closing: Defer closing the response body.

    5. 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:

    1. Create Form Data: Create a url.Values and add form fields.

    2. Send POST Form Request: Use http.PostForm to send the POST request with the form data.

    3. Handle Error: If there is an error, the function panics.

    4. Defer Closing: Defer closing the response body.

    5. 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

  1. Package Declaration and Imports:

     package main
    
     import (
         "encoding/json"
         "fmt"
     )
    
  2. 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 the json:"-" tag.

    • The Tags field is omitted if empty due to the json:"tags,omitempty" tag.

  3. Main Function:

     func main() {
         fmt.Println("Welcome to JSON video")
         // EncodeJson()
         DecodeJson()
     }
    
  4. 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 of course structs and encodes it into a formatted JSON string using json.MarshalIndent.

    • The JSON output is printed to the console.

  5. 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 a course 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 using json.Unmarshal.

Key Points

  • Struct Tags: Use struct tags to control JSON encoding and decoding, e.g., json:"key", json:"-", and json:"omitempty".

  • Encoding JSON: Convert Go structs to JSON using json.Marshal or json.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

  1. Main Application:

    • File: main.go
    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

  1. Modules:

    • Create a Go Module:

      • Run go mod init <module-name> in your project directory. This initializes a new module and creates a go.mod file.

      • Example:

          go mod init mymodule
        
  2. Dependencies:

    • Import Gorilla Mux:

      • Use go get to add the Gorilla Mux package to your project.

      • Example:

          go get github.com/gorilla/mux
        
  3. Setting Up the Server:

    • Router Initialization:

      • Initialize a new router using mux.NewRouter().
    • Define Routes:

      • Define routes using r.HandleFunc(). The serveHome function is set up to handle GET requests to the root path.
    • 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.
  4. Handler Functions:

    • Greeter Function:

      • A simple function to print a greeting message.
    • ServeHome Function:

      • Handles the root path ("/") and responds with an HTML message.

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

  1. Initialize the Module:

     go mod init mymodule
    
  2. Get Dependencies:

     go get github.com/gorilla/mux
    
  3. 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

  1. Main Application:

    • File: main.go
    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

  1. Main Application Setup:

    • Imports: Import necessary packages including encoding/json, fmt, log, math/rand, net/http, strconv, time, and github.com/gorilla/mux.

    • Struct Definitions:

      • Course: Defines the structure of a course with fields CourseId, CourseName, CoursePrice, and Author.

      • Author: Defines the structure of an author with fields Fullname and Website.

    • Fake Database: var courses []Course simulates a database.

    • Middleware/Helper:

      • IsEmpty() bool: Checks if a course's CourseName 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.

  2. 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 (/).
    • 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.
    • 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 and Author).

  • 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

  1. Initialize the Module:

     go mod init mymodule
    
  2. Get Dependencies:

     go get github.com/gorilla/mux
    
  3. Run the Server:

     go run main.go
    

    (type "go build ." in the terminal)

  4. 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 the serveHome 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"
      )
    
  • 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 to true.
    • 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 be application/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.
    • 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

  1. Package and Imports:

     package main
    
     import (
         "fmt"
         "time"
     )
    
    • package main: Defines the package as main, indicating this is an executable program.

    • import "fmt": Imports the fmt package for formatted I/O.

    • import "time": Imports the time package for time-related functions.

  2. 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 the greeter function with the argument "Hello".

    • greeter("world"): Calls the greeter function directly, blocking the main goroutine until it completes.

  3. 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 string s 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 string s to the console.

What Happens When We Run This

  • The main function starts a new goroutine with greeter("Hello") and then immediately calls greeter("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

  1. Package and Imports:

     package main
    
     import (
         "fmt"
         "net/http"
         "sync"
     )
    
    • package main: Defines the package as main, indicating this is an executable program.

    • import "fmt": Imports the fmt package for formatted I/O.

    • import "net/http": Imports the net/http package for making HTTP requests.

    • import "sync": Imports the sync package for synchronization primitives such as WaitGroup and Mutex.

  2. Global Variables:

     var signals = []string{"test"}
    
     var wg sync.WaitGroup //pointer
     var mut sync.Mutex    // pointer
    
    • var signals = []string{"test"}: Initializes a slice named signals with a single element "test".

    • var wg sync.WaitGroup: Declares a WaitGroup named wg to wait for goroutines to finish.

    • var mut sync.Mutex: Declares a Mutex named mut to synchronize access to shared resources.

  3. 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 the websitelist slice.

    • go getStatusCode(web): Launches a new goroutine to execute the getStatusCode function with the current URL as an argument.

    • wg.Add(1): Adds one to the WaitGroup, indicating that there is one more goroutine to wait for.

    • wg.Wait(): Waits for all goroutines to finish. The program will not exit until all wg.Done() calls are made.

    • fmt.Println(signals): Prints the final state of the signals slice.

  4. 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 string endpoint as an argument.

    • defer wg.Done(): Ensures that wg.Done() is called when the function exits, decrementing the WaitGroup counter by one.

    • res, err := http.Get(endpoint): Makes an HTTP GET request to the endpoint URL and stores the response in res and any error in err.

    • if err != nil { ... } else { ... }: Checks if there was an error with the HTTP request.

    • mut.Lock(): Locks the mutex to ensure exclusive access to the signals slice.

    • signals = append(signals, endpoint): Appends the endpoint URL to the signals slice.

    • mut.Unlock(): Unlocks the mutex, allowing other goroutines to access the signals slice.

    • fmt.Printf("%d status code for %s\n", res.StatusCode, endpoint): Prints the HTTP status code and the endpoint 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 the main function waits for all goroutines to complete before printing the final signals slice.

  • The Mutex ensures that only one goroutine can access the signals 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

  1. 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, and sync provides synchronization primitives such as WaitGroup and RWMutex.

  2. 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 a WaitGroup 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 named score with a single element 0.

  3. Adding to WaitGroup:

     wg.Add(3)
    
    • wg.Add(3): Adds three to the WaitGroup, indicating that we have three goroutines to wait for.
  4. 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, appends 1 to the score slice, unlocks the mutex, and calls wg.Done() to indicate it has finished.

    • mut.Lock(): Locks the mutex to ensure exclusive access to the score slice.

    • score = append(score, 1): Appends 1 to the score slice.

    • mut.Unlock(): Unlocks the mutex, allowing other goroutines to access the score slice.

    • wg.Done(): Decrements the WaitGroup counter by one.

  5. 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 the score slice, unlocks the mutex, and calls wg.Done().
  6. 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 the score slice, unlocks the mutex, and calls wg.Done().
  7. 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 the score slice and prints it.

    • mut.RLock(): Locks the mutex for reading, allowing concurrent read access.

    • fmt.Println(score): Prints the score slice.

    • mut.RUnlock(): Unlocks the read lock, allowing other goroutines to access the score slice.

    • wg.Done(): Decrements the WaitGroup counter by one.

  8. Waiting for Goroutines:

     wg.Wait()
     fmt.Println(score)
    
    • wg.Wait(): Waits for all goroutines to finish. The program will not exit until all wg.Done() calls are made.

    • fmt.Println(score): Prints the final state of the score slice.

What Happens When We Run This

  1. Print Message:

  2. Goroutine Execution:

    • Four goroutines are launched. Three of them append values to the score slice while holding a write lock, and one reads the score slice while holding a read lock.

    • The order of execution of these goroutines is not guaranteed and can vary.

  3. Output:

    • The output will show the intermediate states and the final state of the score slice. The final state will contain the initial 0 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

  1. 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, and sync provides synchronization primitives such as WaitGroup.

  2. 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.

  3. Channel Creation:

     myCh := make(chan int, 2)
     wg := &sync.WaitGroup{}
    
    • myCh := make(chan int, 2): Creates a buffered channel myCh that can hold up to 2 integers. Channels are used for communication between goroutines.

    • wg := &sync.WaitGroup{}: Initializes a WaitGroup to wait for the goroutines to finish their execution.

  4. 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.
  5. Adding to WaitGroup:

     wg.Add(2)
    
    • wg.Add(2): Adds two to the WaitGroup, indicating that we have two goroutines to wait for.
  6. 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 the myCh channel and takes a WaitGroup pointer.

    • val, isChanelOpen := <-myCh: Receives a value from myCh. 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.

  7. 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 the myCh channel and takes a WaitGroup pointer.

    • myCh <- 0: Sends the integer 0 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.

  8. Waiting for Goroutines:

     wg.Wait()
    
    • wg.Wait(): Waits for both goroutines to finish. The program will not exit until both wg.Done() calls are made.

What Happens When We Run This

  1. Print Message:

  2. 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 be true for open and false for closed).

  3. Output:

    • The output will be:

        Channels in golang- LearnCodeOnline.in
        true
        0
      
  4. 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.

0
Subscribe to my newsletter

Read articles from Arijit Das directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Arijit Das
Arijit Das