Before You Begin
- Go installed (version 1.21 or later). Download here.
- A text editor (VS Code, GoLand, or even Notepad).
- Basic comfort with your terminal (opening, typing commands).
No prior programming experience? You'll still follow along—I'll explain every piece.
---
The Problem: You Have a Gemstone Collection, and It's Chaos
Imagine you inherited a box of gemstones—rubies, sapphires, emeralds, amethysts. Each has a carat weight, a color, and a value. You need a quick way to add new stones, list everything you own, and maybe someday search, sort, or persist to a file.
Spreadsheets are overkill. Paper gets lost. What you really want is a tiny command-line program that lives in your terminal and does exactly what you need—no bloat.
That program is what we'll build in Go.
---
Step 1: Project Skeleton with Go Modules
Go uses modules to manage dependencies and organise code. Create a new directory and initialise a module:
mkdir gem-cli
cd gem-cli
go mod init gem-cliThis creates a go.mod file. It's just a fingerprint saying "this is the gem-cli module".
Now create a file called main.go. Every Go program starts in package main and runs the main() function.
package main
import "fmt"
func main() {
fmt.Println("Gemstone Inventory v0.1")
}Run it:
go run main.goYou'll see the message. Not impressive yet, but the engine is humming.
---
Step 2: Define a Gemstone – Structs in Go
A gemstone has fixed attributes: name, carat weight, color, and price. In Go we use a struct to bundle these together. The naming convention is Gemstone (exported) because we might use it from other packages later.
Add this above main():
type Gemstone struct {
Name string
Carat float64
Color string
Price float64
}Now you can create a stone like this inside main():
g := Gemstone{Name: "Ruby", Carat: 2.5, Color: "Red", Price: 4500.00}
fmt.Printf("%s: %.1f carat %s - $%.2f\n", g.Name, g.Carat, g.Color, g.Price)Run again. You've just built a data model.
---
Step 3: Store Multiple Stones – Slices
One stone is lonely. We need a collection. Go slices are dynamic arrays. Declare a slice of Gemstone:
var collection []GemstoneAdd stones using append:
collection = append(collection, Gemstone{Name: "Sapphire", Carat: 3.0, Color: "Blue", Price: 6000})
collection = append(collection, Gemstone{Name: "Emerald", Carat: 1.8, Color: "Green", Price: 3200})Now print them all with a simple for loop:
for i, gem := range collection {
fmt.Printf("%d. %s\n", i+1, gem)
}But fmt.Printf with a struct gives ugly output like {Ruby 2.5 Red 4500}. Let's fix that by adding a method.
---
Step 4: Make It Pretty – Methods on Structs
A method is a function attached to a type. Add this after the struct definition:
func (g Gemstone) String() string {
return fmt.Sprintf("%s (%.1f ct, %s) - $%.2f", g.Name, g.Carat, g.Color, g.Price)
}Now fmt.Printf("%s\n", gem) will call this String() method automatically. Re-run and see clean lines.
---
Step 5: Add Interactivity – Reading User Input
The CLI must accept commands. Let's implement a simple loop that asks the user what to do: add a gemstone or list them all.
Replace the main() body with this:
func main() {
collection := []Gemstone{
{Name: "Amethyst", Carat: 1.2, Color: "Purple", Price: 250},
{Name: "Topaz", Carat: 0.9, Color: "Yellow", Price: 180},
}
fmt.Println("Gemstone Inventory Manager")
fmt.Println("Commands: add, list, quit")
for {
fmt.Print("> ")
var cmd string
fmt.Scanln(&cmd)
switch cmd {
case "add":
var name, color string
var carat, price float64
fmt.Print("Name: ")
fmt.Scanln(&name)
fmt.Print("Carat: ")
fmt.Scanln(&carat)
fmt.Print("Color: ")
fmt.Scanln(&color)
fmt.Print("Price: ")
fmt.Scanln(&price)
collection = append(collection, Gemstone{name, carat, color, price})
fmt.Println("Added.")
case "list":
for i, gem := range collection {
fmt.Printf("%d. %s\n", i+1, gem)
}
case "quit":
fmt.Println("Goodbye.")
return
default:
fmt.Println("Unknown command. Try add, list, or quit.")
}
}
}This uses fmt.Scanln for input. Note: Scanln stops at whitespace, so a gem name with a space ("Star Ruby") will read only "Star". For now that's acceptable; later you can switch to bufio.Scanner.
---
Step 6: Build and Run Like a Real Tool
Compile a standalone binary:
go build -o gem-cliNow run it:
./gem-cliYou have a working gemstone inventory manager. Add a few stones, list them, quit. It lives in your terminal.
---
Where to Go Next
This tool is in‑memory only – all data disappears when you quit. Next steps:
- Save and load from a JSON file using
encoding/json. - Add a
searchcommand that filters by color or minimum carat. - Use
flagpackage to accept command‑line arguments instead of an interactive menu. - Write unit tests with
testingpackage – essential for any real software.
---
Common Issues & Fixes
go: go.mod file not found in current directory or any parent directory
Run go mod init gem-cli in the project folder before building.
undefined: Gemstone
Make sure the type Gemstone struct is defined above main() and that there are no typos. Also verify all names are exported (capitalized).
fmt.Scanln skips input
Scanln can behave oddly if there's leftover newline in the buffer. A quick workaround is to use fmt.Scanf with newline handling or switch to bufio.NewReader(os.Stdin).
Binary won't run on another machine
Cross‑compile with GOOS=linux GOARCH=amd64 go build (or for Windows/macOS).
---
---
You've written a real CLI tool in Go from zero. The concepts you learned—structs, slices, methods, user input, loops—are the foundation for everything else in the language. Run with it.

Memuat komentar...