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
7Step-by-step explanation
Numberis a type constraint: it says thatTmay beintorfloat64.add[T Number]is a generic function:Tis a placeholder for a type.add(10, 20)makes Go inferTasint.add(2.5, 1.5)makes Go inferTasfloat64.add[int](3, 4)explicitly tells Go to useint.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."
Tis a type parameter: a placeholder for a type.Numberrestricts which types may be used.a, b Tmeans both parameters have typeT.The final
Tmeans the function returns typeT.
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
trueStep-by-step explanation
nameis a string containing"Go".reflect.ValueOf(&name)creates a reflection value representing the pointer toname..Elem()gets the actual variable that the pointer points to.value.Type()returnsstring.value.String()returns the current string value,"Go".SetString("Golang")changes the original variable.CanSet()returnstruebecause 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."
&namemeans the address ofname.reflect.ValueOfcreates 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.Errorfreports 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
5Step-by-step explanation
add(2, 3)returns5.main()prints5.TestAddis a test function because its name starts withTestand it accepts*testing.T.The test compares the actual result (
got) with the expected result (want).Since both are
5, the test passes.When you run
go test, Go automatically discovers and runsTestAdd.
How to read the important code
func TestAdd(t *testing.T)"func TestAdd, open parenthesis t pointer testing dot T close parenthesis."
*testing.Tis a pointer to Go's test helper.t.Errorf(...)reports a test failure.gotis the actual result.wantis 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
6Step-by-step explanation
testsis a slice containing three test cases.Each struct stores a name, two inputs, and the expected result.
for _, tt := range testsvisits every test case.t.Run(tt.name, ...)runs a separate named subtest.Each subtest calls
multiplywith its own inputs.All three expected results are correct, so all tests pass.
main()prints6.
How to read the important code
for _, tt := range tests"for underscore comma tt colon equals range tests."
rangegoes through the elements of a slice._ignores the index.ttreceives the current test case.t.Runruns 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.Nto 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
25Step-by-step explanation
square(5)returns25.main()prints25.BenchmarkSquareis a benchmark because its name starts withBenchmarkand it accepts*testing.B.b.Nis the number of times Go asks the benchmark to repeat the operation.Go automatically adjusts
b.Nwhen you rungo test -bench=..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.Nis 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
oGStep-by-step explanation
reverse("Go")returns"oG".main()prints"oG".FuzzReverseis a fuzz test because its name starts withFuzz.f.Add("Go")provides a seed input.The fuzz function checks that reversing a string twice returns the original string.
Go can generate additional inputs automatically when you run the fuzz test.
t.Fatalfstops 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.
inputis a string generated by the fuzzing system.t.Fatalfreports 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: 60Step-by-step explanation
pricescontains10,20, and30.totalstarts at0.The first loop adds
10, makingtotal = 10.The second loop adds
20, makingtotal = 30.The third loop adds
30, makingtotal = 60.Each
fmt.Printlndisplays the current price and running total.The function returns
60, whichmain()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 5Step-by-step explanation
make([]int, 3, 5)creates a slice of length3and capacity5.The initial elements are all
0.a[0] = 10anda[1] = 20change the first two elements.b := a[:2]creates a new slice that shares the same underlying array asa.b[0] = 99changes the shared array.Therefore,
a[0]also becomes99.len(a)is3, andcap(a)is5.
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."
makeallocates and initializes certain Go data structures.[]intmeans a slice of integers.3is the length.5is 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
123Step-by-step explanation
builderis astrings.Builder.The loop runs with
i = 1,2, and3.fmt.Sprintf("%d", i)converts each integer into a string.WriteStringappends the string to the builder.The builder contains
"123".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.Builderis designed for efficiently building strings.WriteStringappends text.fmt.Sprintfformats a value into a string.%dmeans "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 failedStep-by-step explanation
nameis a string variable that could hold a database result.rowis declared as a pointer tosql.Row._ = rowprevents the compiler from reporting thatrowis unused.fmt.Errorfcreates an error value.err != nilchecks whether an error occurred.Since an error exists, the program prints the error and returns.
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."
erris commonly used for an error value.nilmeans 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, andExec.
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.