Keyword #
Go hanya punya 25 keyword — salah satu jumlah tersedikit di antara bahasa pemrograman modern. Python punya 35, Java punya 67, C++ punya lebih dari 90. Ini bukan kebetulan. Desainer Go percaya bahwa bahasa yang sederhana menghasilkan kode yang konsisten, mudah dibaca, dan lebih mudah dipelajari. Setiap keyword yang ada di Go punya alasan keberadaannya yang kuat; setiap keyword yang tidak ada juga punya alasan ketiadaannya yang sama kuatnya. Memahami semua 25 keyword Go berarti memahami fondasi dari bahasa itu sendiri.
Semua 25 Keyword Go #
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Dari 25 keyword ini, sebagian besar sudah dibahas di artikel-artikel sebelumnya dalam konteksnya masing-masing. Artikel ini mengumpulkan semuanya dalam satu tempat, mengelompokkannya berdasarkan fungsi, dan membahas nuansa yang mungkin terlewat.
Kelompok 1: Deklarasi #
Keyword yang digunakan untuk mendeklarasikan identitas baru.
package
#
Setiap file Go harus dimulai dengan deklarasi package. Ini menentukan package mana file ini termasuk. Package main adalah satu-satunya yang menghasilkan executable:
package main // executable
package config // library
package utils // library
import
#
Menyertakan package lain untuk digunakan dalam file ini. Import yang tidak dipakai menyebabkan compile error — Go tidak mengizinkan dead import:
import "fmt" // single import
import ( // grouped import — idiomatic
"fmt"
"os"
"strings"
"github.com/gin-gonic/gin"
"myapp/config"
)
var
#
Mendeklarasikan variabel. Bisa di level package maupun di dalam fungsi:
var x int // zero value: 0
var name string = "Budi" // dengan nilai eksplisit
var active = true // type inference
var ( // blok var
host = "localhost"
port = 5432
)
const
#
Mendeklarasikan konstanta yang dievaluasi saat kompilasi. Tidak bisa diisi dengan hasil fungsi runtime:
const pi = 3.14159
const maxRetry = 3
const (
StatusOK = 200
StatusErr = 500
)
const (
Read = 1 << iota // iota hanya valid di dalam blok const
Write // 2
Admin // 4
)
type
#
Mendefinisikan tipe baru. Bisa berbasis tipe yang sudah ada atau mendefinisikan struct dan interface:
type Celsius float64 // type definition
type UserID int64 // membuat tipe bermakna
type Handler func(http.ResponseWriter, *http.Request) // function type
type User struct { // struct type
ID UserID
Name string
}
type Stringer interface { // interface type
String() string
}
type StringMap = map[string]string // type alias (= berarti alias, bukan definisi baru)
func
#
Mendefinisikan fungsi atau method:
func greet(name string) string { // fungsi biasa
return "Halo, " + name
}
func (u User) String() string { // method dengan value receiver
return u.Name
}
func (u *User) SetName(name string) { // method dengan pointer receiver
u.Name = name
}
func divide(a, b float64) (float64, error) { // multiple return values
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
Kelompok 2: Kontrol Aliran #
Keyword yang mengendalikan urutan eksekusi program.
if dan else
#
Percabangan kondisional. Tidak butuh kurung di sekitar kondisi, tapi kurung kurawal wajib:
if x > 0 {
fmt.Println("positif")
} else if x < 0 {
fmt.Println("negatif")
} else {
fmt.Println("nol")
}
// if dengan initializer — sangat idiomatik di Go
if err := doSomething(); err != nil {
return err
}
for
#
Satu-satunya keyword perulangan di Go. Menggantikan while, do-while, dan foreach:
for i := 0; i < 10; i++ { } // classic three-component
for condition { } // while-style
for { } // infinite loop
for i, v := range slice { } // range over collection
for k, v := range mapData { } // range over map
for v := range channel { } // range over channel
switch, case, dan default
#
Percabangan multi-nilai. Tidak ada fallthrough otomatis — setiap case berhenti sendiri:
switch day {
case "Saturday", "Sunday":
fmt.Println("weekend")
default:
fmt.Println("weekday")
}
// switch tanpa ekspresi — pengganti if-else if
switch {
case score >= 90:
grade = "A"
case score >= 80:
grade = "B"
default:
grade = "C"
}
// type switch
switch v := i.(type) {
case int:
fmt.Println("integer:", v)
case string:
fmt.Println("string:", v)
}
break
#
Menghentikan loop atau switch terdekat. Dengan label, bisa menghentikan loop luar:
for i := 0; i < 10; i++ {
if i == 5 {
break // keluar dari loop
}
}
// break dengan label
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer // keluar dari loop luar
}
}
}
continue
#
Melewatkan iterasi saat ini dan lanjut ke iterasi berikutnya. Juga bisa pakai label:
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue // lewati bilangan genap
}
fmt.Println(i)
}
fallthrough
#
Melanjutkan eksekusi ke case berikutnya dalam switch — harus eksplisit, tidak ada fallthrough otomatis:
switch n {
case 1:
fmt.Println("satu")
fallthrough // lanjut ke case 2
case 2:
fmt.Println("dua atau lebih")
}
goto
#
Melompat ke label yang ditandai. Sangat jarang digunakan dalam Go modern — hampir selalu ada alternatif yang lebih bersih:
func contohGoto() {
i := 0
loop:
if i < 5 {
fmt.Println(i)
i++
goto loop // lompat kembali ke label "loop"
}
}
goto di Go punya batasan: tidak bisa melompat ke tempat yang menyebabkan variabel yang sudah dideklarasikan menjadi “terlewat” (untuk menjaga keamanan). Dalam praktik nyata di kode produksi, goto hampir tidak pernah dipakai — for selalu lebih ekspresif dan lebih mudah dibaca.
Kelompok 3: Fungsi dan Goroutine #
return
#
Mengembalikan nilai dari fungsi. Go mendukung multiple return values:
func getUser(id int) (*User, error) {
if id <= 0 {
return nil, errors.New("invalid id") // early return
}
// ...
return user, nil // happy path
}
// Naked return — hanya untuk fungsi pendek dengan named returns
func minMax(nums []int) (min, max int) {
min, max = nums[0], nums[0]
for _, n := range nums[1:] {
if n < min { min = n }
if n > max { max = n }
}
return // mengembalikan min dan max
}
defer
#
Menunda eksekusi statement sampai fungsi yang mengandungnya selesai. Berguna untuk resource cleanup. Beberapa defer dieksekusi LIFO (last in, first out):
func readFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // dijamin dipanggil saat readFile() selesai
// proses file...
return nil
}
func main() {
defer fmt.Println("ketiga") // dieksekusi paling akhir
defer fmt.Println("kedua")
defer fmt.Println("pertama") // dieksekusi paling awal
fmt.Println("berjalan")
}
// Output: berjalan, pertama, kedua, ketiga
go
#
Memulai goroutine — fungsi yang berjalan secara concurrent dengan goroutine pemanggil. Goroutine sangat ringan (mulai ~2KB stack) dibanding OS thread:
go func() {
fmt.Println("berjalan di goroutine baru")
}()
go processRequest(req) // jalankan fungsi bernama sebagai goroutine
// Goroutine dengan komunikasi via channel
results := make(chan int)
go func() {
results <- compute()
}()
fmt.Println(<-results)
Kelompok 4: Tipe Komposit #
struct
#
Mendefinisikan tipe data yang mengelompokkan beberapa field. Pengganti class di Go:
type Point struct {
X, Y float64
}
type Person struct {
Name string
Age int
Address struct { // anonymous nested struct
Street string
City string
}
}
// Embedding struct
type Employee struct {
Person // embedded — field dan method Person tersedia langsung
Department string
Salary float64
}
interface
#
Mendefinisikan kontrak perilaku — kumpulan method signature. Implementasi bersifat implisit (tidak perlu deklarasi implements):
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader // komposisi interface
Writer
}
// Empty interface — bisa menampung tipe apapun
var anything interface{} = 42
var anything2 any = "hello" // any adalah alias interface{} sejak Go 1.18
map
#
Tipe data hash map built-in. Key harus comparable:
m := map[string]int{"satu": 1, "dua": 2}
m2 := make(map[string][]string)
// map sebagai set
seen := map[string]struct{}{}
chan
#
Mendefinisikan tipe channel — saluran komunikasi antar goroutine:
ch := make(chan int) // unbuffered channel
bch := make(chan int, 10) // buffered channel kapasitas 10
rch := make(<-chan int) // receive-only channel
sch := make(chan<- int) // send-only channel
// Kirim dan terima
ch <- 42 // send
v := <-ch // receive
v, ok := <-ch // receive dengan cek apakah channel masih terbuka
Kelompok 5: Alokasi Memory #
new
#
Mengalokasikan memory untuk tipe T, menginisialisasi dengan zero value, mengembalikan *T:
p := new(int) // *int yang menunjuk ke 0
s := new(string) // *string yang menunjuk ke ""
u := new(User) // *User dengan semua field zero value
// Setara dengan:
var x int
p2 := &x
Dalam praktiknya, new jarang dipakai untuk struct — &User{} lebih umum karena bisa langsung mengisi field.
make
#
Membuat dan menginisialisasi slice, map, atau channel. Tidak sama dengan new — make mengembalikan nilai (bukan pointer) yang sudah siap dipakai:
s := make([]int, 5) // slice len=5, cap=5
s2 := make([]int, 0, 100) // slice len=0, cap=100
m := make(map[string]int) // map siap digunakan
m2 := make(map[string]int, 50) // map dengan hint kapasitas 50
ch := make(chan int) // unbuffered channel
ch2 := make(chan int, 10) // buffered channel
Perbedaan new vs make:
new(T) → alokasi T, return *T (pointer ke zero value)
berlaku untuk SEMUA tipe
make(T) → buat dan inisialisasi T, return T (bukan pointer)
HANYA untuk slice, map, dan channel
Hasil sudah siap dipakai (internal state terinisialisasi)
Kelompok 6: Concurrency #
select
#
Seperti switch tapi untuk operasi channel. Menunggu salah satu dari beberapa operasi channel selesai, mengeksekusi case yang pertama siap:
select {
case msg := <-ch1:
fmt.Println("dari ch1:", msg)
case msg := <-ch2:
fmt.Println("dari ch2:", msg)
case ch3 <- "pesan":
fmt.Println("berhasil kirim ke ch3")
case <-time.After(5 * time.Second):
fmt.Println("timeout!")
default:
// non-blocking: jika tidak ada channel yang siap
fmt.Println("tidak ada yang siap")
}
select dengan semua case non-blocking (ada default) tidak akan block — langsung ke default jika tidak ada channel yang siap. Tanpa default, select block sampai minimal satu case siap.
range
#
Mengiterasi slice, array, string, map, atau channel. Mengembalikan dua nilai (index/key dan value):
for i, v := range []int{1, 2, 3} { } // slice/array
for k, v := range map[string]int{} { } // map
for i, r := range "Hello, 世界" { } // string (per rune)
for v := range channel { } // channel (sampai ditutup)
for i := range slice { } // hanya index
// Blank identifier untuk mengabaikan salah satu
for _, v := range slice { } // abaikan index
for i := range slice { } // abaikan value (shorthand)
Keyword yang Sengaja Tidak Ada di Go #
Ini sama pentingnya dengan memahami keyword yang ada. Go secara eksplisit menghilangkan beberapa keyword yang umum di bahasa lain:
TIDAK ADA di Go | Mengapa?
─────────────────────────┼──────────────────────────────────────────────────
class | Digantikan struct + method. Lebih eksplisit,
| tidak perlu hierarki inheritance.
extends / implements | Interface satisfaction bersifat implisit.
| Tidak perlu deklarasi formal.
public / private / | Visibilitas ditentukan huruf besar/kecil:
protected | Exported vs unexported. Lebih ringkas.
abstract / virtual | Go tidak punya inheritance, jadi tidak perlu.
| Polimorfisme via interface.
try / catch / finally | Error adalah nilai return biasa.
throw | Tidak ada exception mechanism tersembunyi.
while / do-while / | Semua digantikan oleh for yang fleksibel.
foreach | Satu keyword untuk semua pola perulangan.
static | Package-level functions/variables sudah "static"
| dalam arti tidak perlu instance.
null / nil-keyword | Go punya nil tapi bukan keyword — ia adalah
| nilai zero untuk pointer, interface, slice, dll.
async / await | Concurrency via goroutine + channel, bukan
| promise/future model.
this / self | Receiver diberi nama eksplisit oleh developer:
| func (u *User) Save() {}
** (operator pangkat) | Bukan keyword tapi operator — gunakan math.Pow()
?: (ternary operator) | Tidak ada. Gunakan if-else yang lebih jelas.
Ringkasan Visual Semua 25 Keyword #
DEKLARASI (6):
package → deklarasi package file ini
import → menyertakan package lain
var → deklarasi variabel
const → deklarasi konstanta (compile-time)
type → mendefinisikan tipe baru
func → mendefinisikan fungsi atau method
KONTROL ALIRAN (10):
if → percabangan kondisional
else → cabang alternatif dari if
for → perulangan (satu-satunya di Go)
switch → percabangan multi-nilai
case → case dalam switch atau select
default → case default dalam switch/select
break → hentikan loop atau switch
continue → lewati iterasi saat ini
fallthrough → lanjut ke case berikutnya (switch)
goto → lompat ke label (jarang dipakai)
FUNGSI & GOROUTINE (3):
return → kembalikan nilai dari fungsi
defer → tunda eksekusi hingga fungsi selesai
go → mulai goroutine baru
TIPE KOMPOSIT (4):
struct → tipe dengan kumpulan field
interface → kontrak perilaku (kumpulan method)
map → tipe hash map key-value
chan → tipe channel untuk komunikasi goroutine
ALOKASI (2):
new → alokasi zero value, return pointer
make → buat & inisialisasi slice/map/chan
CONCURRENCY (2):
select → tunggu operasi channel
range → iterasi koleksi
Contoh Program Lengkap #
Program berikut menggunakan hampir semua keyword Go dalam satu konteks yang kohesif — sebuah sistem antrian task concurrent sederhana:
package main // keyword: package
import ( // keyword: import
"fmt"
"sync"
"time"
)
// keyword: type, struct
type TaskStatus int
const ( // keyword: const
StatusPending TaskStatus = iota
StatusRunning
StatusDone
StatusFailed
)
func (s TaskStatus) String() string { // keyword: func
switch s { // keyword: switch
case StatusPending: // keyword: case
return "Pending"
case StatusRunning:
return "Running"
case StatusDone:
return "Done"
default: // keyword: default
return "Failed"
}
}
// keyword: type, struct
type Task struct {
ID int
Name string
Status TaskStatus
Result string
fn func() (string, error)
}
// keyword: type, interface
type Queue interface {
Submit(name string, fn func() (string, error)) int
Wait()
Results() []Task
}
// keyword: type, struct
type WorkerPool struct {
tasks []Task // keyword: var tidak eksplisit (field struct)
taskCh chan Task // keyword: chan
resultCh chan Task
wg sync.WaitGroup
mu sync.Mutex
nextID int
}
// keyword: func
func NewWorkerPool(workers int) *WorkerPool {
// keyword: var
var p = &WorkerPool{
taskCh: make(chan Task, 100), // keyword: make
resultCh: make(chan Task, 100),
}
// Jalankan workers — keyword: for, go
for i := 0; i < workers; i++ {
p.wg.Add(1)
go func() { // keyword: go
defer p.wg.Done() // keyword: defer
for task := range p.taskCh { // keyword: for, range
task.Status = StatusRunning
result, err := task.fn()
if err != nil { // keyword: if
task.Status = StatusFailed
task.Result = err.Error()
} else { // keyword: else
task.Status = StatusDone
task.Result = result
}
p.resultCh <- task
}
}()
}
// Kumpulkan results di goroutine terpisah
go func() {
p.wg.Wait()
close(p.resultCh)
}()
return p // keyword: return
}
func (p *WorkerPool) Submit(name string, fn func() (string, error)) int {
p.mu.Lock()
defer p.mu.Unlock()
p.nextID++
task := Task{
ID: p.nextID,
Name: name,
Status: StatusPending,
fn: fn,
}
p.tasks = append(p.tasks, task)
p.taskCh <- task
return task.ID
}
func (p *WorkerPool) Wait() {
close(p.taskCh)
// Kumpulkan semua results — keyword: for, range, select
done := make(chan struct{})
go func() {
for result := range p.resultCh {
p.mu.Lock()
for i := range p.tasks {
if p.tasks[i].ID == result.ID {
p.tasks[i] = result
break // keyword: break
}
}
p.mu.Unlock()
}
close(done)
}()
// Tunggu dengan timeout — keyword: select
select {
case <-done:
// selesai normal
case <-time.After(30 * time.Second):
fmt.Println("Timeout menunggu tasks")
}
}
func (p *WorkerPool) Results() []Task {
p.mu.Lock()
defer p.mu.Unlock()
// Salin slice dengan new allocation — keyword: new tidak dipakai di sini
// tapi gunakan make untuk slice baru
result := make([]Task, len(p.tasks))
copy(result, p.tasks)
return result
}
func main() { // keyword: func, juga entry point
pool := NewWorkerPool(3) // 3 goroutine worker
// Submit beberapa task
tasks := []struct {
name string
fn func() (string, error)
}{
{"Ambil data user", func() (string, error) {
time.Sleep(100 * time.Millisecond)
return "42 users ditemukan", nil
}},
{"Proses pembayaran", func() (string, error) {
time.Sleep(200 * time.Millisecond)
return "Rp 5.000.000 berhasil diproses", nil
}},
{"Kirim email", func() (string, error) {
time.Sleep(150 * time.Millisecond)
return "3 email terkirim", nil
}},
{"Backup database", func() (string, error) {
time.Sleep(300 * time.Millisecond)
return "Backup selesai: 2.3GB", nil
}},
{"Generate laporan", func() (string, error) {
time.Sleep(250 * time.Millisecond)
return "Laporan Q4 siap", nil
}},
}
// keyword: for, range
for _, t := range tasks {
id := pool.Submit(t.name, t.fn)
fmt.Printf("Task #%d '%s' disubmit\n", id, t.name)
}
fmt.Println("\nMenunggu semua task selesai...")
pool.Wait()
fmt.Println("\n=== Hasil Task ===")
// keyword: for, range
for _, task := range pool.Results() {
status := "✓"
// keyword: if
if task.Status == StatusFailed {
status = "✗"
}
fmt.Printf("[%s] #%d %-25s → %s\n",
status, task.ID, task.Name, task.Result)
}
// keyword: var — deklarasi eksplisit
var total int = len(pool.Results())
fmt.Printf("\nSelesai. Total task: %d\n", total)
}
Ringkasan #
- Go hanya punya 25 keyword — sedikit secara sengaja untuk menjaga bahasa tetap sederhana dan konsisten.
- 6 keyword deklarasi:
package,import,var,const,type,func.- 10 keyword kontrol aliran:
if,else,for,switch,case,default,break,continue,fallthrough,goto.- 3 keyword fungsi & goroutine:
return,defer,go.- 4 keyword tipe komposit:
struct,interface,map,chan.- 2 keyword alokasi:
new(pointer ke zero value, semua tipe) danmake(siap pakai, khusus slice/map/chan).- 2 keyword concurrency:
select(tunggu channel) danrange(iterasi koleksi).gotoada tapi hampir tidak pernah dipakai —forselalu lebih ekspresif.- Tidak ada:
class,extends,implements,try/catch,while,async/await,this, ternary?:— semua dihilangkan secara sengaja dengan alasan desain yang kuat.- Memahami 25 keyword ini berarti memahami seluruh fondasi sintaks Go — tidak ada keyword tersembunyi atau kejutan.