GO 41 to 50

Chapter 41 — Generics

Question

Given below is a code snippet that:

  • Demonstrates a generic function.

  • Uses one function with different data types.

  • Demonstrates a type parameter and a type constraint.

  • Demonstrates how Go infers the type automatically.

What should be the output of the following code?

package main

import "fmt"

type Number interface {
	int | float64
}

func add[T Number](a, b T) T {
	return a + b
}

func main() {
	fmt.Println(add(10, 20))
	fmt.Println(add(2.5, 1.5))
	fmt.Println(add[int](3, 4))
}

Answer

30
4
7

Step-by-step explanation

  1. Number is a type constraint: it says that T may be int or float64.

  2. add[T Number] is a generic function: T is a placeholder for a type.

  3. add(10, 20) makes Go infer T as int.

  4. add(2.5, 1.5) makes Go infer T as float64.

  5. add[int](3, 4) explicitly tells Go to use int.

  6. The function returns the sum using the same type.

How to read the important code

func add[T Number](a, b T) T

"func add, square bracket T Number square bracket, open parenthesis a comma b T close parenthesis T."

  • T is a type parameter: a placeholder for a type.

  • Number restricts which types may be used.

  • a, b T means both parameters have type T.

  • The final T means the function returns type T.

Key takeaway

Generics let you write one reusable function that works with multiple types while keeping type safety.


Chapter 42 — Reflection

Question

Given below is a code snippet that:

  • Demonstrates reflection using reflect.

  • Inspects the type and value of a variable.

  • Demonstrates changing a value through reflection.

  • Demonstrates why a value must be addressable before it can be changed.

What should be the output of the following code?

package main

import (
	"fmt"
	"reflect"
)

func main() {
	name := "Go"

	value := reflect.ValueOf(&name).Elem()

	fmt.Println(value.Type())
	fmt.Println(value.String())

	value.SetString("Golang")

	fmt.Println(name)
	fmt.Println(value.CanSet())
}

Answer

string
Go
Golang
true

Step-by-step explanation

  1. name is a string containing "Go".

  2. reflect.ValueOf(&name) creates a reflection value representing the pointer to name.

  3. .Elem() gets the actual variable that the pointer points to.

  4. value.Type() returns string.

  5. value.String() returns the current string value, "Go".

  6. SetString("Golang") changes the original variable.

  7. CanSet() returns true because the reflection value represents an addressable variable.

How to read the important code

value := reflect.ValueOf(&name).Elem()

"value colon equals reflect dot ValueOf, open parenthesis ampersand name close parenthesis, dot Elem, open parenthesis close parenthesis."

  • &name means the address of name.

  • reflect.ValueOf creates a reflection value.

  • .Elem() means "get the value stored at this pointer."

  • Reflection allows a program to inspect or sometimes modify values at runtime.

Key takeaway

Reflection lets Go inspect values at runtime, but it is more complex and slower than ordinary Go code, so use it only when necessary.


Chapter 43 — Testing with testing

Question

Given below is a code snippet that:

  • Demonstrates a basic Go test.

  • Uses a function that returns a value.

  • Demonstrates a passing test.

  • Demonstrates how t.Errorf reports a failure.

What should be the output of the following code?

package main

import (
	"fmt"
	"testing"
)

func add(a, b int) int {
	return a + b
}

func TestAdd(t *testing.T) {
	got := add(2, 3)
	want := 5

	if got != want {
		t.Errorf("add(2, 3) = %d; want %d", got, want)
	}
}

func main() {
	fmt.Println(add(2, 3))
}

Answer

5

Step-by-step explanation

  1. add(2, 3) returns 5.

  2. main() prints 5.

  3. TestAdd is a test function because its name starts with Test and it accepts *testing.T.

  4. The test compares the actual result (got) with the expected result (want).

  5. Since both are 5, the test passes.

  6. When you run go test, Go automatically discovers and runs TestAdd.

How to read the important code

func TestAdd(t *testing.T)

"func TestAdd, open parenthesis t pointer testing dot T close parenthesis."

  • *testing.T is a pointer to Go's test helper.

  • t.Errorf(...) reports a test failure.

  • got is the actual result.

  • want is the expected result.

Key takeaway

A Go test checks whether actual behavior matches the expected behavior.


Chapter 44 — Table-Driven Tests

Question

Given below is a code snippet that:

  • Demonstrates a table-driven test.

  • Stores multiple test cases in a slice of structs.

  • Uses a loop to run each case.

  • Demonstrates how the same test logic can test different inputs.

What should be the output of the following code?

package main

import (
	"fmt"
	"testing"
)

func multiply(a, b int) int {
	return a * b
}

func TestMultiply(t *testing.T) {
	tests := []struct {
		name string
		a    int
		b    int
		want int
	}{
		{"positive", 2, 3, 6},
		{"zero", 5, 0, 0},
		{"negative", -2, 3, -6},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := multiply(tt.a, tt.b)

			if got != tt.want {
				t.Errorf("got %d; want %d", got, tt.want)
			}
		})
	}
}

func main() {
	fmt.Println(multiply(2, 3))
}

Answer

6

Step-by-step explanation

  1. tests is a slice containing three test cases.

  2. Each struct stores a name, two inputs, and the expected result.

  3. for _, tt := range tests visits every test case.

  4. t.Run(tt.name, ...) runs a separate named subtest.

  5. Each subtest calls multiply with its own inputs.

  6. All three expected results are correct, so all tests pass.

  7. main() prints 6.

How to read the important code

for _, tt := range tests

"for underscore comma tt colon equals range tests."

  • range goes through the elements of a slice.

  • _ ignores the index.

  • tt receives the current test case.

  • t.Run runs a named subtest.

Key takeaway

Table-driven tests let you test many inputs using one consistent test structure.


Chapter 45 — Benchmarks

Question

Given below is a code snippet that:

  • Demonstrates a benchmark function.

  • Uses b.N to control the number of repetitions.

  • Demonstrates the difference between a benchmark and an ordinary function.

  • Demonstrates how Go measures repeated work.

What should be the output of the following code?

package main

import (
	"fmt"
	"testing"
)

func square(n int) int {
	return n * n
}

func BenchmarkSquare(b *testing.B) {
	for i := 0; i < b.N; i++ {
		square(i)
	}
}

func main() {
	fmt.Println(square(5))
}

Answer

25

Step-by-step explanation

  1. square(5) returns 25.

  2. main() prints 25.

  3. BenchmarkSquare is a benchmark because its name starts with Benchmark and it accepts *testing.B.

  4. b.N is the number of times Go asks the benchmark to repeat the operation.

  5. Go automatically adjusts b.N when you run go test -bench=..

  6. The benchmark measures how long the repeated calls take.

How to read the important code

for i := 0; i < b.N; i++ {

"for i colon equals zero; i is less than b dot N; i plus plus; open curly brace."

  • b.N is controlled by the benchmark framework.

  • The loop repeats the operation many times.

  • A benchmark measures performance, not correctness.

Key takeaway

Benchmarks measure how efficiently code runs under repeated execution.


Chapter 46 — Fuzz Testing

Question

Given below is a code snippet that:

  • Demonstrates a fuzz test.

  • Uses a seed value.

  • Adds a fuzzing input.

  • Demonstrates a property that should always remain true.

What should be the output of the following code?

package main

import (
	"fmt"
	"strings"
	"testing"
)

func reverse(s string) string {
	runes := []rune(s)

	for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
		runes[i], runes[j] = runes[j], runes[i]
	}

	return string(runes)
}

func FuzzReverse(f *testing.F) {
	f.Add("Go")

	f.Fuzz(func(t *testing.T, input string) {
		if !strings.EqualFold(reverse(reverse(input)), input) {
			t.Fatalf("reverse twice changed input")
		}
	})
}

func main() {
	fmt.Println(reverse("Go"))
}

Answer

oG

Step-by-step explanation

  1. reverse("Go") returns "oG".

  2. main() prints "oG".

  3. FuzzReverse is a fuzz test because its name starts with Fuzz.

  4. f.Add("Go") provides a seed input.

  5. The fuzz function checks that reversing a string twice returns the original string.

  6. Go can generate additional inputs automatically when you run the fuzz test.

  7. t.Fatalf stops the current test immediately if the property fails.

How to read the important code

f.Fuzz(func(t *testing.T, input string) {

"f dot Fuzz, open parenthesis func, open parenthesis t pointer testing dot T comma input string, close parenthesis, open curly brace."

  • A fuzz test automatically tries many inputs.

  • input is a string generated by the fuzzing system.

  • t.Fatalf reports a failure and stops the current test.

Key takeaway

Fuzz testing helps discover unexpected bugs by trying many automatically generated inputs.


Chapter 47 — Debugging & Profiling

Question

Given below is a code snippet that:

  • Demonstrates a common debugging technique.

  • Uses a function to calculate a result.

  • Demonstrates printing intermediate values.

  • Demonstrates how a profiler can help identify expensive work.

What should be the output of the following code?

package main

import "fmt"

func calculateTotal(prices []int) int {
	total := 0

	for _, price := range prices {
		total += price
		fmt.Println("debug:", price, total)
	}

	return total
}

func main() {
	prices := []int{10, 20, 30}
	fmt.Println("total:", calculateTotal(prices))
}

Answer

debug: 10 10
debug: 20 30
debug: 30 60
total: 60

Step-by-step explanation

  1. prices contains 10, 20, and 30.

  2. total starts at 0.

  3. The first loop adds 10, making total = 10.

  4. The second loop adds 20, making total = 30.

  5. The third loop adds 30, making total = 60.

  6. Each fmt.Println displays the current price and running total.

  7. The function returns 60, which main() prints.

How to read the important code

fmt.Println("debug:", price, total)

"fmt dot Println, open parenthesis double quote debug colon double quote comma price comma total close parenthesis."

  • This is a debug print: temporary output used to understand what the program is doing.

  • A profiler measures where a program spends time or memory.

  • Debugging finds incorrect behavior; profiling finds performance bottlenecks.

Key takeaway

Debugging helps explain what the program does; profiling helps explain where it spends resources.


Chapter 48 — Memory Management & Garbage Collection

Question

Given below is a code snippet that:

  • Demonstrates allocating memory using make.

  • Demonstrates a slice and its underlying array.

  • Demonstrates how two slices can share the same underlying array.

  • Demonstrates how Go's garbage collector manages memory automatically.

What should be the output of the following code?

package main

import "fmt"

func main() {
	a := make([]int, 3, 5)
	a[0] = 10
	a[1] = 20

	b := a[:2]
	b[0] = 99

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(len(a), cap(a))
}

Answer

[99 20 0]
[99 20]
3 5

Step-by-step explanation

  1. make([]int, 3, 5) creates a slice of length 3 and capacity 5.

  2. The initial elements are all 0.

  3. a[0] = 10 and a[1] = 20 change the first two elements.

  4. b := a[:2] creates a new slice that shares the same underlying array as a.

  5. b[0] = 99 changes the shared array.

  6. Therefore, a[0] also becomes 99.

  7. len(a) is 3, and cap(a) is 5.

How to read the important code

a := make([]int, 3, 5)

"a colon equals make, open parenthesis square bracket int close square bracket, three comma five close parenthesis."

  • make allocates and initializes certain Go data structures.

  • []int means a slice of integers.

  • 3 is the length.

  • 5 is the capacity: the amount of underlying storage available before a new allocation may be needed.

Key takeaway

Go manages memory automatically, but understanding slices and shared storage is essential for avoiding unexpected mutations.


Chapter 49 — Performance Optimization

Question

Given below is a code snippet that:

  • Demonstrates the difference between repeated string concatenation and strings.Builder.

  • Demonstrates how a builder accumulates text.

  • Demonstrates the final string produced by the builder.

  • Demonstrates a common performance optimization used in Go.

What should be the output of the following code?

package main

import (
	"fmt"
	"strings"
)

func main() {
	var builder strings.Builder

	for i := 1; i <= 3; i++ {
		builder.WriteString(fmt.Sprintf("%d", i))
	}

	fmt.Println(builder.String())
}

Answer

123

Step-by-step explanation

  1. builder is a strings.Builder.

  2. The loop runs with i = 1, 2, and 3.

  3. fmt.Sprintf("%d", i) converts each integer into a string.

  4. WriteString appends the string to the builder.

  5. The builder contains "123".

  6. String() returns the final string.

How to read the important code

builder.WriteString(fmt.Sprintf("%d", i))

"builder dot WriteString, open parenthesis fmt dot Sprintf, open parenthesis double quote percent d double quote comma i close parenthesis, close parenthesis."

  • strings.Builder is designed for efficiently building strings.

  • WriteString appends text.

  • fmt.Sprintf formats a value into a string.

  • %d means "format this integer as a decimal number."

Key takeaway

Performance optimization means reducing unnecessary work while keeping the code correct and readable.


Chapter 50 — Database Programming with database/sql

Question

Given below is a code snippet that:

  • Demonstrates the structure of a database query using database/sql.

  • Demonstrates scanning a row into variables.

  • Demonstrates checking an error.

  • Demonstrates why database operations must handle errors.

What should be the output of the following code?

package main

import (
	"database/sql"
	"fmt"
)

func main() {
	var name string

	var row *sql.Row

	_ = row

	err := fmt.Errorf("database connection failed")

	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("name:", name)
}

Answer

error: database connection failed

Step-by-step explanation

  1. name is a string variable that could hold a database result.

  2. row is declared as a pointer to sql.Row.

  3. _ = row prevents the compiler from reporting that row is unused.

  4. fmt.Errorf creates an error value.

  5. err != nil checks whether an error occurred.

  6. Since an error exists, the program prints the error and returns.

  7. The final fmt.Println("name:", name) is never executed.

How to read the important code

if err != nil {

"if err is not equal to nil, open curly brace."

  • err is commonly used for an error value.

  • nil means no value for certain types, including pointers and error interfaces.

  • != means "not equal to."

  • In real database code, you check the error returned by operations such as QueryRow, Scan, and Exec.

Key takeaway

Database programming is mostly about executing queries, reading results, and handling errors safely.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.