Pemrograman Go dari Nol dengan 25 Contoh
Go (Golang) adalah bahasa yang dikembangkan di Google. Bahasa ini sederhana, cepat dikompilasi, dan mendukung konkurensi secara bawaan, sehingga populer untuk server, perkakas, dan sistem cloud. Artikel ini memiliki 25 contoh kode, yang masing-masing dijalankan dengan Go 1.27, dengan keluaran sebenarnya dari setiap contoh. Contohnya bergerak dari dasar sampai konkurensi, handler web, dan generics.
Yang Anda butuhkan
Pasang Go dari go.dev/dl lalu periksa dengan `go version`. Buat berkas `.go` dan jalankan dengan `go run namafile.go`.
Ilustrasi
Contoh 1: Halo, dunia
Program Go paling sederhana. Setiap program dimulai dengan paket main dan fungsi main.
package main
import "fmt"
func main() {
fmt.Println("Halo Go")
}
Keluaran sebenarnya
Halo Go
Contoh 2: Variabel dan konstanta
`:=` mendeklarasikan dan memberi nilai dalam satu langkah, `var` mendeklarasikan secara eksplisit, dan `const` untuk nilai yang tidak pernah berubah.
package main
import "fmt"
const schoolName = "Sekolah Contoh"
func main() {
name := "Budi"
var age int = 20
fmt.Println(schoolName, name, age)
}
Keluaran sebenarnya
Sekolah Contoh Budi 20
Contoh 3: Nilai nol
Variabel yang dideklarasikan tanpa nilai akan mendapat nilai nol dari tipenya, seperti 0, string kosong, atau false.
package main
import "fmt"
func main() {
var n int
var s string
var b bool
var f float64
fmt.Printf("int=%d string=%q bool=%t float=%.1f\n", n, s, b, f)
}
Keluaran sebenarnya
int=0 string="" bool=false float=0.0
Contoh 4: if dan else
Pengambilan keputusan dengan if dan else if. Go tidak memerlukan tanda kurung di sekitar kondisi.
package main
import "fmt"
func main() {
score := 72
if score >= 80 {
fmt.Println("A")
} else if score >= 70 {
fmt.Println("B")
} else {
fmt.Println("C")
}
}
Keluaran sebenarnya
B
Contoh 5: Perulangan for
Go hanya memiliki satu kata kunci perulangan, yaitu for, yang bisa menghitung atau bertindak seperti while.
package main
import "fmt"
func main() {
for i := 1; i <= 3; i++ {
fmt.Println("hitung", i)
}
n := 0
for n < 2 {
n++
}
fmt.Println("n =", n)
}
Keluaran sebenarnya
hitung 1
hitung 2
hitung 3
n = 2
Contoh 6: switch
switch membandingkan beberapa kasus dan tidak lanjut ke kasus berikutnya kecuali Anda memintanya.
package main
import "fmt"
func main() {
day := "Sabtu"
switch day {
case "Sabtu", "Minggu":
fmt.Println("hari libur")
default:
fmt.Println("hari kerja")
}
}
Keluaran sebenarnya
hari libur
Contoh 7: Array dan slice
Array memiliki ukuran tetap. Slice bertambah dengan append dan bisa dipotong dengan s[a:b].
package main
import "fmt"
func main() {
arr := [3]int{1, 2, 3}
s := []int{10, 20}
s = append(s, 30, 40)
fmt.Println("array:", arr, "len:", len(arr))
fmt.Println("slice:", s, "len:", len(s), "cap:", cap(s) >= 4)
fmt.Println("irisan:", s[1:3])
}
Keluaran sebenarnya
array: [1 2 3] len: 3
slice: [10 20 30 40] len: 4 cap: true
irisan: [20 30]
Contoh 8: Map
Map menyimpan pasangan kunci-nilai. Bentuk `v, ok :=` memeriksa apakah sebuah kunci ada.
package main
import "fmt"
func main() {
scores := map[string]int{"Budi": 85, "Siti": 72}
scores["Andi"] = 45
if v, ok := scores["Budi"]; ok {
fmt.Println("nilai:", v)
}
delete(scores, "Siti")
fmt.Println("jumlah:", len(scores))
}
Keluaran sebenarnya
nilai: 85
jumlah: 2
Contoh 9: Fungsi dengan beberapa nilai kembali
Sebuah fungsi dapat mengembalikan beberapa nilai. Error biasanya dikembalikan sebagai nilai terakhir.
package main
import (
"errors"
"fmt"
)
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("tidak bisa dibagi nol")
}
return a / b, nil
}
func main() {
q, err := divide(10, 2)
fmt.Println("hasil:", q, "error:", err)
_, err = divide(1, 0)
fmt.Println("error:", err)
}
Keluaran sebenarnya
hasil: 5 error: <nil>
error: tidak bisa dibagi nol
Contoh 10: Closure
Fungsi yang mengingat variabel dari lingkup di sekitarnya. Berguna untuk penghitung dan state pribadi.
package main
import "fmt"
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next(), next(), next())
}
Keluaran sebenarnya
1 2 3
Contoh 11: Struct dan method
Struct mengelompokkan beberapa data, dan method memberikan perilaku pada tipe tersebut.
package main
import "fmt"
type Student struct {
Name string
Score int
}
func (s Student) Grade() string {
if s.Score >= 80 {
return "A"
}
return "B"
}
func main() {
s := Student{Name: "Budi", Score: 85}
fmt.Println(s.Name, s.Grade())
}
Keluaran sebenarnya
Budi A
Contoh 12: Interface
Interface mendaftar method yang harus dimiliki sebuah tipe. Tipe mana pun yang memiliki method tersebut otomatis memenuhi interface.
package main
import "fmt"
type Shape interface {
Area() float64
}
type Rect struct{ W, H float64 }
func (r Rect) Area() float64 { return r.W * r.H }
func main() {
var s Shape = Rect{W: 3, H: 4}
fmt.Printf("luas = %.1f\n", s.Area())
}
Keluaran sebenarnya
luas = 12.0
Contoh 13: Pointer
&x memberikan alamat sebuah variabel dan *p membaca atau mengubah nilai di alamat itu, sehingga fungsi dapat mengubah data pemanggilnya.
package main
import "fmt"
func increment(n *int) {
*n++
}
func main() {
x := 5
increment(&x)
fmt.Println("x =", x)
}
Keluaran sebenarnya
x = 6
Contoh 14: Menangani error
Buat error dengan fmt.Errorf dan %w, lalu periksa dengan errors.Is untuk melihat apakah sebuah error cocok dengan error yang sudah dikenal.
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("data tidak ditemukan")
func find(id int) error {
if id != 1 {
return fmt.Errorf("kode %d: %w", id, ErrNotFound)
}
return nil
}
func main() {
err := find(2)
fmt.Println(err)
fmt.Println("cocok dengan ErrNotFound:", errors.Is(err, ErrNotFound))
}
Keluaran sebenarnya
kode 2: data tidak ditemukan
cocok dengan ErrNotFound: true
Contoh 15: defer
defer menunda pemanggilan sampai fungsi di sekitarnya selesai. Cocok untuk menutup berkas dan melepaskan sumber daya.
package main
import "fmt"
func main() {
defer fmt.Println("dijalankan terakhir")
fmt.Println("mulai")
fmt.Println("memproses")
}
Keluaran sebenarnya
mulai
memproses
dijalankan terakhir
Contoh 16: panic dan recover
panic menghentikan eksekusi normal, dan recover hanya bisa menangkapnya di dalam fungsi yang di-defer, sehingga program tidak crash.
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("pulih dari panic: %v", r)
}
}()
return a / b, nil
}
func main() {
fmt.Println(safeDivide(10, 2))
fmt.Println(safeDivide(1, 0))
}
Keluaran sebenarnya
5 <nil>
0 pulih dari panic: runtime error: integer divide by zero
Contoh 17: Goroutine
Kata kunci go memulai pekerjaan yang berjalan secara konkuren. sync.WaitGroup menunggu sampai semua pekerjaan selesai.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
_ = n * n
}(i)
}
wg.Wait()
fmt.Println("semua tugas selesai")
}
Keluaran sebenarnya
semua tugas selesai
Contoh 18: Channel
Channel mengirim nilai di antara goroutine. Contoh ini mengirim nilai dari goroutine ke main, lalu menutup channel.
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 3; i++ {
ch <- i * 10
}
close(ch)
}()
for v := range ch {
fmt.Println("menerima", v)
}
}
Keluaran sebenarnya
menerima 10
menerima 20
menerima 30
Contoh 19: select dan timeout
select menunggu beberapa channel sekaligus. time.After menetapkan waktu tunggu maksimum.
package main
import (
"fmt"
"time"
)
func main() {
result := make(chan string)
go func() {
time.Sleep(200 * time.Millisecond)
result <- "selesai"
}()
select {
case msg := <-result:
fmt.Println(msg)
case <-time.After(50 * time.Millisecond):
fmt.Println("waktu habis")
}
}
Keluaran sebenarnya
waktu habis
Contoh 20: Mutex untuk data bersama
sync.Mutex memungkinkan banyak goroutine mengubah satu variabel dengan aman. Totalnya selalu benar.
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
var wg sync.WaitGroup
total := 0
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
total++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("total =", total)
}
Keluaran sebenarnya
total = 100
Contoh 21: Paket strings dan rune
strings menyediakan fungsi teks. len menghitung byte, jadi hitung karakter non-ASCII dengan mengubah ke []rune.
package main
import (
"fmt"
"strings"
)
func main() {
s := "Go mudah dipelajari"
fmt.Println(strings.ToUpper("go"), strings.Contains(s, "mudah"))
fmt.Println(strings.Split("a,b,c", ","), len("café"), len([]rune("café")))
fmt.Println([]rune("café")[3] == 'é')
}
Keluaran sebenarnya
GO true
[a b c] 5 4
true
Contoh 22: Membaca dan menulis berkas
os.WriteFile dan os.ReadFile menulis dan membaca seluruh berkas dalam satu pemanggilan.
package main
import (
"fmt"
"os"
)
func main() {
if err := os.WriteFile("note.txt", []byte("catatan dari Go\n"), 0644); err != nil {
fmt.Println("gagal menulis:", err)
return
}
data, err := os.ReadFile("note.txt")
if err != nil {
fmt.Println("gagal membaca:", err)
return
}
fmt.Print("terbaca: ", string(data))
}
Keluaran sebenarnya
terbaca: catatan dari Go
Contoh 23: JSON
encoding/json mengubah struct menjadi JSON dan sebaliknya. Tag seperti `json:"..."` menetapkan nama field.
package main
import (
"encoding/json"
"fmt"
)
type Student struct {
Name string `json:"name"`
Score int `json:"score"`
}
func main() {
b, _ := json.Marshal(Student{Name: "Budi", Score: 85})
fmt.Println(string(b))
var s Student
_ = json.Unmarshal([]byte(`{"name":"Siti","score":72}`), &s)
fmt.Println(s.Name, s.Score)
}
Keluaran sebenarnya
{"name":"Budi","score":85}
Siti 72
Contoh 24: Menguji handler HTTP
httptest menguji fungsi handler tanpa menjalankan server sungguhan.
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Halo dari Go HTTP")
}
func main() {
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
hello(rec, req)
body, _ := io.ReadAll(rec.Result().Body)
fmt.Println(rec.Code, string(body))
}
Keluaran sebenarnya
200 Halo dari Go HTTP
Contoh 25: Generics
Fungsi yang bekerja pada beberapa tipe dengan memakai parameter tipe T, yang dibatasi oleh interface.
package main
import "fmt"
type Number interface {
~int | ~float64
}
func Sum[T Number](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
func main() {
fmt.Println(Sum([]int{1, 2, 3}))
fmt.Println(Sum([]float64{1.5, 2.5}))
}
Keluaran sebenarnya
6
4
Langkah berikutnya
Cobalah menulis server web yang menerima JSON dan menyimpannya ke berkas. Setelah itu, pelajari paket net/http dan context untuk timeout serta pembatalan.
Ringkasan
Go memiliki sintaks yang sederhana, memeriksa tipe saat kompilasi, menangani error sebagai nilai, dan mendukung konkurensi dengan goroutine dan channel, sehingga cocok untuk server dan beban kerja dengan banyak tugas.