This episode guides you through writing your first Go program: file structure, package declarations, imports, and go run. You will also learn basic data types, variables, constants, operators, functions with multiple return values, and idiomatic error handling.

In episode 2 you saw the map of Go's architecture. Now it's time for you to start typing. Episode 3 takes you through writing your first Go program from scratch, understanding file structure and package declarations, and then mastering data types, variables, constants, operators, functions, and idiomatic error handling.
Every concept in this episode is a building block for the rest of the series. Make sure you run each example with go run in your terminal, rather than just reading them.
Every Go file begins with a package declaration. The file containing the entry point uses package main and must have a main function.
package main
import "fmt"
func main() {
fmt.Println("Halo, dunia Go!")
}Run it with go run main.go. This command compiles the file temporarily and then executes it. To produce a permanent binary, use go build main.go and then run ./main.
Go is very disciplined: unused imports and declared-but-unused variables are compile errors, not just warnings. Variables that really aren't needed can be captured with _ (the blank identifier).
Go provides a full set of basic types: bool, string, integers such as int and int64, floats such as float64, plus byte as an alias for uint8 and rune as an alias for int32. Choosing the right integer type matters for memory efficiency.
package main
import "fmt"
func main() {
var nama string = "Arman"
var umur int = 30
aktif := true
const versi = "1.23.0"
fmt.Println(nama, umur, aktif, versi)
}The syntax aktif := true is a short variable declaration — the type is inferred from the value. Constants are declared with const and cannot be changed after initialization.
Go supports the standard arithmetic, comparison, and logical operators. Go's quirk: ++ and -- are statements, not expressions — so x = x++ is not valid.
package main
import "fmt"
func main() {
a, b := 10, 3
fmt.Println("jumlah:", a+b)
fmt.Println("bagi:", a/b)
fmt.Println("modulo:", a%b)
fmt.Println("perbandingan:", a > b)
}Functions are declared with the func keyword. One of Go's signature traits: a function can return several values at once. The most common pattern is returning a result and an error together.
package main
import "fmt"
func bagi(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("tidak bisa membagi dengan nol")
}
return a / b, nil
}
func main() {
hasil, err := bagi(10, 4)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("hasil:", hasil)
}Notice that fmt.Errorf("...") wraps an error message and nil means no error. The pattern hasil, err := ... followed by checking if err != nil is the idiom that dominates the entire Go ecosystem.
Go handles errors explicitly: every operation that can fail returns an error as a value, and the caller is required to check it. There are no exceptions jumping between functions. The error flow is always visible and treated as plain data.
package main
import (
"fmt"
"strconv"
)
func main() {
teks := "123"
angka, err := strconv.Atoi(teks)
if err != nil {
fmt.Println("konversi gagal:", err)
return
}
fmt.Println("angka:", angka+1)
}strconv.Atoi converts a string to an integer and returns an error when the input is invalid.
When propagating errors upward, get into the habit of wrapping them with %w so the higher-layer context is preserved without losing the original error:
func simpanFile(path string) error {
file, err := os.Create(path)
if err != nil {
return fmt.Errorf("gagal membuat file: %w", err)
}
defer file.Close()
return nil
}The %w format keeps the original error accessible via errors.Is and errors.As — we will dissect the full details in episode 6.
The "declared and not used" error appears when a variable isn't used; remove the variable or replace it with _. The short declaration := is only valid inside functions; at package level use var. Also, Go doesn't convert types implicitly — int and float64 cannot be added directly without an explicit conversion like float64(a).
These small exercises train you to think about types from the very beginning. Discipline like this is what makes Go code easy for others to read in large teams.
Episode 3 is your syntactic foundation: Go file structure with package main and the main function, basic data types, variables and constants, operators, functions with multiple return values, and the idiomatic error handling pattern with if err != nil.
Key takeaways:
main is the entry point.:= for short declarations, const for fixed values.%w to wrap errors so context is preserved.In the next episode we will discuss modularization, packages, and dependency management — creating a module with go mod init, importing local and external packages, managing module versions, and writing reusable packages documented with go doc. Your code will start to be organized as a real project.