My Learning Blog

Some basic and small projects in golang - 10/23/2024

coding in go

Project 1

To parse an HTML file to count the number of words and pictures:

package main

import (
	"fmt"
	"golang.org/x/net/html"
	"io"
	"net/http"
	"strings"
)

// Function to count words and images in the HTML
func countWordsAndImages(r io.Reader) (int, int) {
	doc, err := html.Parse(r)
	if err != nil {
		fmt.Println("Error parsing HTML:", err)
		return 0, 0
	}

	var wordCount,imageCount int
  dfs(doc, &wordCount, &imageCpunt)
  return wordCount,inmageCount
}

func dfs(*html.Node, *wordCount,*imageCount ){

		if n.Type == html.TextNode {
			words := strings.Fields(n.Data)
			wordCount += len(words)
		}
		if n.Type == html.ElementNode && n.Data == "img" {
			imageCount++
		}
		// Recursively traverse the HTML nodes
		for c := n.FirstChild; c != nil; c = c.NextSibling {
      dfs(c,wordsCount,imageCount)
		}

}

func main() {
	// Example: Fetch an HTML page (or you can parse from a file)
	resp, err := http.Get("https://example.com")
	if err != nil {
		fmt.Println("Error fetching page:", err)
		return
	}
  // The caller must close the response body when finished with it:
	defer resp.Body.Close()

	// Count words and images in the page
	wordCount, imageCount := countWordsAndImages(resp.Body)

	fmt.Printf("Word Count: %d\n", wordCount)
	fmt.Printf("Image Count: %d\n", imageCount)
}

Basic to know

var m map[string]string vs m = map[string]string{}

  1. var m map[string]string Declaring a map like this creates a nil map. A nil map behaves like an empty map when reading values, but any attempt to write to it (e.g., adding a key-value pair) will result in a runtime panic.
var m map[string]string
fmt.Println(m == nil) // true

// Reading from it is fine, but it returns the zero value
value := m["key"] // value is ""

m["key"] = "value" // PANIC: assignment to entry in nil map

Use Case: var m map[string]string is often used when you don’t need to initialize the map right away or will initialize it later, such as in a function.

  1. m = map[string]string{} Using m = map[string]string{} creates an empty map and allocates memory for it, meaning it is ready for both reading and writing. You can safely add key-value pairs to this map without causing a panic.
m := map[string]string{} // or m = make(map[string]string)
m["key"] = "value"       // This is fine; no panic
fmt.Println(m["key"])    // Outputs: value

Use Case: This form is used when you want a map that is ready to use immediately, allowing both reads and writes without risk of runtime errors.

Slice Initialization

package main

import "fmt"

func main() {
    a := make([]int, 0) // Empty slice
    b := []int{}        // Empty slice

    // Attempting to assign to a[0] will panic
    a[0] = 2 // PANIC: runtime error: index out of range [0] with length 0
    b[0] = 2 // PANIC: runtime error: index out of range [0] with length 0
}

To modify or assign to a[0], the slice must have at least one element. You can achieve this by either:

// use make to create a slice with a specific length:
a := make([]int, 1) // Length = 1, Capacity = 1
a[0] = 2            // Valid
fmt.Println(a)      // Output: [2]
// use append
a := make([]int, 0) // Or a := []int{}
a = append(a, 2)    // Add an element
a[0] = 3            // Now valid
fmt.Println(a)      // Output: [3]