Go Programming — Block 2: Files, Data, and Project Structure
Chapters 11–20 · Beginner-friendly · Practical examples · Complete answers included
Block 1 taught you the foundations: variables, conditions, loops, functions, slices, maps, strings, and basic debugging.
Block 2 teaches you to build programs that organize information, save data, read files, and use multiple source files.
Since you will publish this material in a Blogspot post, every MCQ, practical exercise, and challenge will include its answer or a complete working solution. Nothing will depend on an instructor being present to explain the missing steps.
What you will learn
11. Pointers — only the practical basics
Understand how a function can change a variable belonging to its caller.
12. Structs and custom data types
Group a product's name, price, and stock into one record.
13. Methods and interfaces
Attach actions to your own data types and understand how different types can satisfy the same behavior.
14. Packages and modules
Organize code across files and folders without making one enormous source file.
15. Reading and writing files
Save information and load it again after a program closes.
16. JSON and data conversion
Exchange structured data with websites, APIs, and other programs.
17. Error handling
Detect problems such as missing files and invalid data instead of letting them go unnoticed.
18. Dates, times, and standard libraries
Work with dates, timestamps, formatting, and useful built-in tools.
19. Testing your code
Automatically check whether your functions return the correct results.
20. Project structure and Git basics
Arrange a real project, track code changes, and recover earlier versions.
Chapter 11 — Pointers: changing information through a function
A pointer sounds complicated, but the basic idea is simple.
Imagine that price is a box containing 100. A pointer gives a function a way to access that same box, rather than just receiving a separate copy of the number.
MCQ 1
What happens when you pass a normal integer variable to a function in Go?
A. The function automatically receives a pointer.
B. The function receives a copy of the integer value.
C. The original variable is deleted.
D. Go refuses to pass integers to functions.
Correct answer: B.
Go passes the value. For an integer, the function receives a copy, so changing its local parameter does not change the caller's variable.
MCQ 2
What will this program print?
Go
package main
import "fmt"
func changeValue(number *int) {
*number = 50
}
func main() {
price := 100
changeValue(&price)
fmt.Println(price)
}A.
100B.
50C.
0D. A compilation error
Correct answer: B — 50.
Why?
&priceobtains a pointer toprice.number *intmeans thatnumberis a pointer to an integer.*number = 50changes the value at the location that the pointer refers to.Therefore, the original
pricebecomes50.
Practical task — Increase a product's price
Save as main.go.
Go
package main
import "fmt"
func increasePrice(price *float64) {
*price = *price + 10
}
func main() {
price := 100.0
increasePrice(&price)
fmt.Println("Updated price:", price)
}Output:
Updated price: 110Real-life use: A function may need to update a product's stock, change an account setting, or modify a record supplied by the calling code.
Remember: You do not need pointers everywhere. Use them when you need to modify a value through a pointer or when the design calls for sharing access to data. Go still passes pointer values by value.
Chapter 12 — Structs and custom data types
A struct groups related pieces of information into one record.
Imagine you have a product. Instead of maintaining separate lists for product names, prices, and stock quantities, you can keep the information for each product together.
MCQ 3
Which Go feature is designed to group related fields such as a product's name, price, and quantity?
A. Struct
B. Loop
C. Comment
D. Import statement
Correct answer: A — Struct.
MCQ 4
What will this code print?
Go
type Product struct {
Name string
Price float64
}
func main() {
item := Product{Name: "Book", Price: 50}
fmt.Println(item.Name)
}A.
ProductB.
50C.
BookD. Nothing
Correct answer: C — Book.
item.Name accesses the Name field of the product record.
Practical task — Create a product record
Folder structure:
product-app/
└── main.goCode:
Go
package main
import "fmt"
type Product struct {
Name string
Price float64
Quantity int
}
func main() {
item := Product{
Name: "Notebook",
Price: 40,
Quantity: 5,
}
total := item.Price * float64(item.Quantity)
fmt.Println("Product:", item.Name)
fmt.Println("Stock:", item.Quantity)
fmt.Println("Stock value:", total)
}Output:
Product: Notebook
Stock: 5
Stock value: 200Line-by-line concepts
type Product structdefines a new data structure.Name,Price, andQuantityare fields.Product{...}creates a value containing those fields.item.Priceaccesses the price.float64(item.Quantity)converts the quantity to a decimal-compatible numeric type.Multiplying the price by the quantity calculates the total stock value.
Real-life use: Product catalogs, student records, customer details, employee information, and order records.
Chapter 13 — Methods and interfaces
A method is a function associated with a particular type.
An interface describes behavior: for example, any type that can provide a Total() method returning a float64 can satisfy an interface that requires that method.
MCQ 5
What is the primary purpose of a method?
A. To associate an operation with a type.
B. To create a new folder.
C. To install Go.
D. To replace all variables.
Correct answer: A.
MCQ 6
Consider this code:
Go
type Product struct {
Price float64
Quantity int
}
func (p Product) Total() float64 {
return p.Price * float64(p.Quantity)
}How can you calculate the total for a product stored in item?
A.
item.Total()B.
Product.TotalC.
item.Price()D.
Total.Product()
Correct answer: A — item.Total().
Practical task — Give a product its own calculation method
Go
package main
import "fmt"
type Product struct {
Name string
Price float64
Quantity int
}
func (p Product) Total() float64 {
return p.Price * float64(p.Quantity)
}
func main() {
item := Product{
Name: "Pen",
Price: 10,
Quantity: 8,
}
fmt.Println("Product:", item.Name)
fmt.Println("Total:", item.Total())
}Output:
Product: Pen
Total: 80The expression func (p Product) Total() defines a method on Product. The variable p represents the product being used.
A small interface example
Go
type Totaler interface {
Total() float64
}Any type with a matching Total() float64 method satisfies this interface automatically. You don't have to explicitly declare that it implements the interface.
When do you need interfaces? When different kinds of objects need to be used through the same behavior. Learn the basic idea now; advanced interface design can wait until you build larger applications.
Chapter 14 — Packages, modules, and multiple files
You do not have to put your entire program into one file. Go lets you organize code into packages and directories.
A package groups related Go source files. A module identifies a Go project and its dependencies.
MCQ 7
What is the main purpose of a Go module?
A. To identify a Go project and manage its dependencies.
B. To print messages.
C. To replace every function.
D. To make all code public automatically.
Correct answer: A.
MCQ 8
If two .go files are in the same directory and both declare package main, can they normally be compiled together as one executable?
A. No, Go only allows one source file per program.
B. Yes, provided their declarations do not conflict.
C. Only if both files have the same filename.
D. Only if neither file contains functions.
Correct answer: B.
Practical task — Split a program into two files
Folder structure:
greeting-app/
├── go.mod
├── main.go
└── greeting.goCreate the module from inside greeting-app:
Bash
go mod init example.com/greeting-appThe command creates go.mod. You do not need to type the generated module file manually.
main.go:
Go
package main
import "fmt"
func main() {
message := greeting("Pramod")
fmt.Println(message)
}greeting.go:
Go
package main
func greeting(name string) string {
return "Hello, " + name
}Run the project from the folder containing go.mod:
Bash
go run .Output:
Hello, PramodImportant: Both files belong to package main, so the function in greeting.go is available to main.go. When compiling a package, Go compiles the relevant source files together.
When should you create a separate package?
Create separate packages when code forms a useful, reusable group with a clear responsibility. Merely splitting every function into a different folder creates unnecessary complexity.
Chapter 15 — Reading and writing files
So far, information stored in variables disappears when the program ends. Files allow a program to save information for later.
MCQ 9
What is the main advantage of saving information to a file?
A. The information can be read again after the program closes.
B. The program no longer needs variables.
C. All errors disappear.
D. The file automatically becomes a database.
Correct answer: A.
MCQ 10
Which standard-library package provides common file-reading and file-writing functions?
A.
fmtB.
osC.
mathD.
strings
Correct answer: B — os. The os package provides functions such as ReadFile and WriteFile.
Practical task — Save and read a note
Folder structure:
file-app/
└── main.goCode:
Go
package main
import (
"fmt"
"os"
)
func main() {
err := os.WriteFile(
"note.txt",
[]byte("Learn Go every day."),
0644,
)
if err != nil {
fmt.Println("Could not save the note:", err)
return
}
data, err := os.ReadFile("note.txt")
if err != nil {
fmt.Println("Could not read the note:", err)
return
}
fmt.Println(string(data))
}Run:
Bash
go run main.goOutput:
Learn Go every day.The program also creates note.txt in its working directory.
Understand the important lines:
os.WriteFilewrites data to a file. If the file does not exist, it creates it.[]byte(...)converts text into bytes, which are the units used to represent file data.0644sets the file's permission bits on systems that support those permissions.err != nilchecks whether the operation returned an error.os.ReadFileloads the file's contents into memory.string(data)converts the bytes into text.
Real-life use: Saving reports, exporting results, storing configuration, and writing simple logs.
For a simple example, this is enough. For multiple users, concurrent writes, or important business data, you need stronger data-management techniques.
Chapter 16 — JSON and data conversion
JSON is a common format for exchanging structured information between applications. It can represent objects, arrays, strings, numbers, Booleans, and null values.
For example:
JSON
{
"name": "Notebook",
"price": 40,
"quantity": 5
}MCQ 11
What is JSON commonly used for?
A. Exchanging structured data between applications.
B. Increasing the computer's physical memory.
C. Replacing all programming languages.
D. Creating hardware.
Correct answer: A.
MCQ 12
Which Go package provides JSON encoding and decoding?
A.
encoding/jsonB.
fmt/jsonC.
os/jsonD.
strings/json
Correct answer: A — encoding/json.
Practical task — Convert a product into JSON
Go
package main
import (
"encoding/json"
"fmt"
)
type Product struct {
Name string `json:"name"`
Price float64 `json:"price"`
Quantity int `json:"quantity"`
}
func main() {
item := Product{
Name: "Notebook",
Price: 40,
Quantity: 5,
}
data, err := json.MarshalIndent(item, "", " ")
if err != nil {
fmt.Println("Could not create JSON:", err)
return
}
fmt.Println(string(data))
}Output:
JSON
{
"name": "Notebook",
"price": 40,
"quantity": 5
}What matters here?
encoding/jsoncontains Go's standard JSON tools.json.MarshalIndentconverts a Go value into readable JSON bytes.The tags, such as
json:"name", specify the JSON field names.string(data)converts the generated bytes into printable text.The error check handles a failed conversion.
Practical extension — Decode JSON
To turn JSON back into a Go value, use json.Unmarshal.
Go
var item Product
err := json.Unmarshal(data, &item)
if err != nil {
fmt.Println("Invalid JSON:", err)
return
}Here, data must contain valid JSON bytes, and item receives the decoded product. The &item pointer allows the function to fill in the struct's fields.
Real-life use: API responses, application settings, exported data, and communication between a website and a Go backend.
Chapter 17 — Error handling
An error is information that tells you an operation failed. Go functions commonly return an error value so your program can decide what to do next.
MCQ 13
What does this condition check?
Go
if err != nil {
fmt.Println("Something went wrong")
}A. Whether the program has finished successfully.
B. Whether an error value exists.
C. Whether a variable is a string.
D. Whether a loop should start.
Correct answer: B. In Go, nil represents the absence of a value for certain types, including the built-in error interface. If err != nil, an error was reported.
MCQ 14
A program tries to read a file that does not exist. What should a reliable program generally do?
A. Pretend the file was read successfully.
B. Check the returned error and respond appropriately.
C. Ignore all errors.
D. Delete every other file.
Correct answer: B.
Practical task — Handle a missing file
Go
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("missing.txt")
if err != nil {
fmt.Println("File could not be read.")
return
}
fmt.Println(string(data))
}If missing.txt does not exist in the working directory, the program prints:
File could not be read.Why not ignore the error? If you try to process the file's contents without checking whether the read succeeded, your program may produce confusing results or fail later.
Practical rule: Whenever a Go function returns an error, understand what the function promises and handle the error appropriately. Do not automatically ignore it.
Chapter 18 — Dates, times, and useful standard libraries
Go includes many standard-library packages, so you can solve common tasks without installing extra dependencies.
The time package handles dates, times, durations, and formatting.
MCQ 15
Which package is commonly used to work with dates and times in Go?
A.
timeB.
fmtC.
osD.
strings
Correct answer: A — time.
MCQ 16
What does time.Now() return?
A. The current time as a
time.Timevalue.B. The number of files on your computer.
C. A random number.
D. A formatted JSON document.
Correct answer: A.
Practical task — Display the current date and time
Go
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("Current date and time:", now.Format("2006-01-02 15:04:05"))
fmt.Println("Year:", now.Year())
fmt.Println("Month:", now.Month())
}Example output:
Current date and time: 2026-10-03 10:30:45
Year: 2026
Month: OctoberThe example output is illustrative; your actual date and time will depend on when and where you run the program.
A special Go rule: The layout "2006-01-02 15:04:05" is Go's reference layout for formatting dates and times. You use those reference numbers to indicate the desired format.
Real-life use: Recording when an order was placed, creating timestamps for logs, calculating durations, and displaying dates in reports.
Other useful standard-library packages include:
math— mathematical functions.strconv— converting strings and numeric values.path/filepath— working with file paths.sort— sorting values.net/http— building HTTP clients and servers.
Learn a package when a practical task requires it rather than memorizing the entire standard library.
Chapter 19 — Testing your code
Testing means checking that a program produces the expected result. Automated tests let you repeat those checks whenever you change your code.
MCQ 17
What is the purpose of a unit test?
A. To check a small piece of code independently.
B. To install an operating system.
C. To replace all comments.
D. To guarantee that a program has no possible bugs.
Correct answer: A. A unit test checks a function or another small unit of behavior. Passing tests do not prove that every possible bug has been eliminated.
MCQ 18
What command runs Go tests in the current module and its subpackages?
A.
go startB.
go test ./...C.
go deleteD.
go install all-tests
Correct answer: B — go test ./....
Practical task — Write your first automated test
Folder structure:
math-app/
├── go.mod
├── math.go
└── math_test.goInitialize the project:
Bash
go mod init example.com/math-appmath.go:
Go
package main
func Add(a int, b int) int {
return a + b
}math_test.go:
Go
package main
import "testing"
func TestAdd(t *testing.T) {
result := Add(3, 4)
if result != 7 {
t.Errorf("Add(3, 4) = %d; want 7", result)
}
}Run the test from the project directory:
Bash
go testExpected output will include:
PASS
okThe exact output also includes the package path and execution time.
How it works:
Test files normally end in
_test.go.Test functions begin with
Testand accept*testing.T.Add(3, 4)calls the function.The
ifcondition compares the actual result with the expected result.t.Errorf(...)reports a failure if the values do not match.
Real-life use: After modifying a discount calculation, you can run the tests again to check that the calculation still works.
Chapter 20 — Project structure and Git basics
As programs grow, you need two forms of organization:
Project structure: Keep related code in sensible files and folders.
Version control: Track changes so you can understand what changed and return to an earlier saved version when needed.
Git is a tool for tracking changes to files. GitHub is a hosting service where you can store and share Git repositories.
MCQ 19
What is the main purpose of Git?
A. Track changes to files and versions of a project.
B. Execute Go code automatically without a compiler.
C. Replace the Go programming language.
D. Create databases automatically.
Correct answer: A.
MCQ 20
What does git status show?
A. The current state of the working directory and staging area.
B. The current price of a product.
C. The contents of every database on your computer.
D. The result of every Go test ever written.
Correct answer: A. It helps you see which files are modified, untracked, or staged for a commit.
Practical task — Track a Go project using Git
Start with:
my-go-project/
├── go.mod
└── main.goFrom inside the project directory, initialize Git:
Bash
git initCreate a .gitignore file if needed:
*.exe
*.test
.envThis example ignores Windows executable files, Go test binaries, and a common environment-file name. Add other generated files or local secrets as appropriate for your project.
Check the repository:
Bash
git statusStage the files you want to track:
Bash
git add go.mod main.go .gitignoreSave a snapshot of the staged changes:
Bash
git commit -m "Initial Go project"If Git asks you to configure your name and email, configure them for your own commits before retrying.
What the commands mean:
git initcreates a local Git repository.git statusshows the state of the repository.git addstages changes for the next commit.git commitrecords the staged snapshot in the project's history.
Real-life use: You can experiment with a feature, compare changes, review what you modified, and collaborate with other developers. Git does not automatically upload your project to GitHub; publishing a remote repository requires additional setup.
Block 2 — Combined Practical Project
Build a product inventory manager
You will now combine structs, methods, slices, JSON, files, error handling, dates, and tests in one small project.
The application will:
Store product information.
Calculate stock value.
Save product data to a JSON file.
Load saved information when needed.
Display a timestamp.
Include an automated test.
This is a local learning project, not a production inventory system.
1. Folder structure
Create the following files:
inventory-app/
├── go.mod
├── main.go
├── inventory.go
└── inventory_test.goInitialize the module inside inventory-app:
Bash
go mod init example.com/inventory-app2. File: inventory.go
This file defines the product structure and its calculations, along with the functions that save and load inventory data.
Go
package main
import (
"encoding/json"
"os"
)
type Product struct {
Name string `json:"name"`
Price float64 `json:"price"`
Quantity int `json:"quantity"`
}
func (p Product) StockValue() float64 {
return p.Price * float64(p.Quantity)
}
func SaveInventory(filename string, products []Product) error {
data, err := json.MarshalIndent(products, "", " ")
if err != nil {
return err
}
return os.WriteFile(filename, data, 0644)
}
func LoadInventory(filename string) ([]Product, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
var products []Product
err = json.Unmarshal(data, &products)
if err != nil {
return nil, err
}
return products, nil
}Understand the important parts
Productgroups the name, price, and quantity.StockValue()calculates the total value of a product's stock.SaveInventory()converts the slice into JSON and writes it to a file.LoadInventory()reads the file and converts the JSON back into a slice.erroris returned to the caller when an operation fails.return nil, errindicates that no usable product slice is being returned alongside the error.
3. File: main.go
Go
package main
import (
"fmt"
"os"
"time"
)
func main() {
filename := "inventory.json"
products := []Product{
{Name: "Notebook", Price: 40, Quantity: 20},
{Name: "Pen", Price: 10, Quantity: 50},
{Name: "Bag", Price: 500, Quantity: 5},
}
if err := SaveInventory(filename, products); err != nil {
fmt.Println("Save failed:", err)
return
}
savedProducts, err := LoadInventory(filename)
if err != nil {
fmt.Println("Load failed:", err)
return
}
fmt.Println("INVENTORY REPORT")
fmt.Println("Generated:", time.Now().Format("2006-01-02 15:04:05"))
totalValue := 0.0
for _, product := range savedProducts {
value := product.StockValue()
totalValue += value
fmt.Printf(
"%s | Price: %.2f | Quantity: %d | Value: %.2f\n",
product.Name,
product.Price,
product.Quantity,
value,
)
}
fmt.Printf("Total inventory value: %.2f\n", totalValue)
if _, err := os.Stat(filename); err == nil {
fmt.Println("Inventory file saved successfully.")
}
}4. File: inventory_test.go
Go
package main
import "testing"
func TestStockValue(t *testing.T) {
product := Product{
Name: "Notebook",
Price: 40,
Quantity: 5,
}
got := product.StockValue()
want := 200.0
if got != want {
t.Errorf("StockValue() = %v; want %v", got, want)
}
}5. Run the application
From the project directory:
Bash
go run .Expected output, with the timestamp varying according to your computer's clock:
INVENTORY REPORT
Generated: 2026-10-03 10:30:45
Notebook | Price: 40.00 | Quantity: 20 | Value: 800.00
Pen | Price: 10.00 | Quantity: 50 | Value: 500.00
Bag | Price: 500.00 | Quantity: 5 | Value: 2500.00
Total inventory value: 3800.00
Inventory file saved successfully.The program creates inventory.json in the working directory. Open it to see the saved product records in JSON format.
Run the automated test:
Bash
go test ./...The test checks that a product priced at 40 with a quantity of 5 has a stock value of 200.
Important limitation: This introductory application recreates and saves the sample inventory each time it runs. It demonstrates saving and loading, but it does not yet preserve user edits or provide an interactive inventory menu. Those are natural extensions for later projects.
Final Block 2 Skill Test
Try these questions before opening the answer key.
10 MCQs
0/10 answered
1. What does `&price` give you?
A. A copy of the price as a string
B. A pointer to the price variable
C. A JSON document
D. A new file
2. What is a struct used for?
A. Repeating a task
B. Grouping related fields
C. Installing packages
D. Formatting dates
3. Which statement about Go interfaces is correct?
A. Every type must declare implements explicitly
B. An interface describes required methods
C. Interfaces are only for printing
D. Interfaces replace structs
4. What does `go run .` do inside a Go module directory?
A. Runs the package in the current directory
B. Deletes the module
C. Runs all tests only
D. Uploads the project to GitHub
5. What does `os.ReadFile` return?
A. Only a Boolean
B. File contents and an error
C. A database connection
D. A timestamp
6. Which package handles JSON conversion?
A. encoding/json
B. time/json
C. fmt/json
D. os/json
7. What should you normally do if a file operation returns a non-nil error?
A. Always ignore it
B. Check and handle the failure
C. Assume the file exists
D. Convert the error to a date
8. What does `time.Now()` provide?
A. The current date and time
B. The current Git commit
C. A random duration
D. The number of files
9. What is the purpose of a Go test?
A. Check expected behavior automatically
B. Replace every application function
C. Guarantee zero bugs
D. Install third-party software
10. What does `git commit` do?
A. Records staged changes in repository history
B. Runs a Go application
C. Reads a JSON file
D. Creates a struct
Check all answers
Final practical challenges — with solutions
Challenge 1: Update a struct
Create a Product struct with a name and price. Change the price from 100 to 125.
Show complete solution
Challenge 2: Save data
Save the text Go is useful to message.txt, then read and print it.
Show complete solution
Challenge 3: Test a calculation
Write a function that doubles an integer and create a test that verifies double(5) equals 10.
Show complete solution
What you should be able to do after Block 2
Group information using structs and attach useful methods.
Understand basic pointers and interfaces.
Split a Go application across source files and initialize a module.
Save and load information using files and JSON.
Check errors instead of ignoring failed operations.
Work with dates and standard-library tools.
Write basic automated tests.
Use Git to track changes to a project.
You do not need to master every advanced feature of pointers, interfaces, or package design yet. The aim is to use these building blocks confidently.
Next: Block 3 moves into command-line applications, databases, SQL, HTTP, web servers, REST APIs, forms, authentication, and deployment — the skills that begin turning your Go knowledge into usable applications.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.