diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f242d25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Dependency directories +vendor/ + +# Go module cache +root/ + +# Build artifacts +examples/01_datatypes +examples/02_variables +examples/03_operators +examples/04_controlflow +examples/05_functions +examples/06_arrays_slices +examples/07_maps +examples/08_structs +examples/09_interfaces +examples/10_concurrency +examples/11_errorhandling diff --git a/README.md b/README.md index 8a75182..231adf7 100644 --- a/README.md +++ b/README.md @@ -1 +1,527 @@ -# golang-basic \ No newline at end of file +# Golang Basic - Penjelasan Dasar Golang + +Repository ini berisi penjelasan dan contoh-contoh dasar pemrograman Golang (Go). + +## Daftar Isi + +1. [Pengenalan Golang](#pengenalan-golang) +2. [Instalasi](#instalasi) +3. [Konsep Dasar](#konsep-dasar) +4. [Tipe Data](#tipe-data) +5. [Variabel dan Konstanta](#variabel-dan-konstanta) +6. [Operator](#operator) +7. [Kontrol Alur](#kontrol-alur) +8. [Fungsi](#fungsi) +9. [Array dan Slice](#array-dan-slice) +10. [Map](#map) +11. [Struct](#struct) +12. [Interface](#interface) +13. [Goroutine dan Channel](#goroutine-dan-channel) +14. [Error Handling](#error-handling) + +## Pengenalan Golang + +Go (atau Golang) adalah bahasa pemrograman yang dikembangkan oleh Google pada tahun 2007 dan dirilis sebagai open source pada tahun 2009. Go dirancang untuk: + +- **Sederhana dan mudah dipelajari**: Sintaks yang bersih dan minimal +- **Cepat**: Kompilasi yang cepat dan performa yang tinggi +- **Concurrent**: Dukungan bawaan untuk pemrograman konkuren dengan goroutine +- **Scalable**: Cocok untuk membangun aplikasi yang scalable +- **Produktif**: Tools yang lengkap dan standard library yang kuat + +## Instalasi + +Untuk menginstal Golang, kunjungi [https://golang.org/dl/](https://golang.org/dl/) dan ikuti instruksi untuk sistem operasi Anda. + +Verifikasi instalasi: +```bash +go version +``` + +## Konsep Dasar + +### Hello World + +```go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, World!") +} +``` + +Untuk menjalankan: +```bash +go run main.go +``` + +## Tipe Data + +Go memiliki beberapa tipe data dasar: + +### Tipe Data Numerik + +- **Integer**: `int`, `int8`, `int16`, `int32`, `int64` +- **Unsigned Integer**: `uint`, `uint8`, `uint16`, `uint32`, `uint64` +- **Float**: `float32`, `float64` +- **Complex**: `complex64`, `complex128` + +### Tipe Data Lainnya + +- **Boolean**: `bool` (true/false) +- **String**: `string` +- **Byte**: `byte` (alias untuk uint8) +- **Rune**: `rune` (alias untuk int32, merepresentasikan Unicode code point) + +Lihat contoh: [examples/01_datatypes.go](examples/01_datatypes.go) + +## Variabel dan Konstanta + +### Deklarasi Variabel + +Ada beberapa cara mendeklarasikan variabel: + +```go +// Cara 1: Dengan tipe data eksplisit +var name string = "John" + +// Cara 2: Type inference +var age = 25 + +// Cara 3: Short declaration (hanya di dalam fungsi) +city := "Jakarta" + +// Cara 4: Multiple variables +var x, y int = 1, 2 +``` + +### Konstanta + +```go +const Pi = 3.14159 +const ( + StatusOK = 200 + StatusNotFound = 404 +) +``` + +Lihat contoh: [examples/02_variables.go](examples/02_variables.go) + +## Operator + +### Operator Aritmatika +- `+` (penjumlahan) +- `-` (pengurangan) +- `*` (perkalian) +- `/` (pembagian) +- `%` (modulus) + +### Operator Perbandingan +- `==` (sama dengan) +- `!=` (tidak sama dengan) +- `<` (lebih kecil) +- `>` (lebih besar) +- `<=` (lebih kecil atau sama dengan) +- `>=` (lebih besar atau sama dengan) + +### Operator Logika +- `&&` (AND) +- `||` (OR) +- `!` (NOT) + +Lihat contoh: [examples/03_operators.go](examples/03_operators.go) + +## Kontrol Alur + +### If-Else + +```go +if age >= 18 { + fmt.Println("Dewasa") +} else { + fmt.Println("Anak-anak") +} + +// If dengan statement pendek +if score := 85; score >= 80 { + fmt.Println("Lulus dengan baik") +} +``` + +### Switch + +```go +switch day { +case "Senin": + fmt.Println("Awal minggu") +case "Jumat": + fmt.Println("Akhir minggu kerja") +default: + fmt.Println("Hari biasa") +} +``` + +### For Loop + +```go +// For loop standar +for i := 0; i < 5; i++ { + fmt.Println(i) +} + +// While-style loop +for count < 10 { + count++ +} + +// Infinite loop +for { + // loop tanpa henti + break // gunakan break untuk keluar +} + +// Range loop +numbers := []int{1, 2, 3, 4, 5} +for index, value := range numbers { + fmt.Printf("Index: %d, Value: %d\n", index, value) +} +``` + +Lihat contoh: [examples/04_controlflow.go](examples/04_controlflow.go) + +## Fungsi + +```go +// Fungsi sederhana +func greet(name string) { + fmt.Printf("Hello, %s!\n", name) +} + +// Fungsi dengan return value +func add(a int, b int) int { + return a + b +} + +// Multiple return values +func divide(a, b float64) (float64, error) { + if b == 0 { + return 0, fmt.Errorf("division by zero") + } + return a / b, nil +} + +// Named return values +func calculate(a, b int) (sum int, product int) { + sum = a + b + product = a * b + return // naked return +} + +// Variadic function +func sum(numbers ...int) int { + total := 0 + for _, num := range numbers { + total += num + } + return total +} +``` + +Lihat contoh: [examples/05_functions.go](examples/05_functions.go) + +## Array dan Slice + +### Array + +Array memiliki ukuran tetap: + +```go +var arr [5]int +arr[0] = 1 +arr[1] = 2 + +// Inisialisasi array +numbers := [5]int{1, 2, 3, 4, 5} +``` + +### Slice + +Slice memiliki ukuran dinamis: + +```go +// Membuat slice +slice := []int{1, 2, 3} + +// Append ke slice +slice = append(slice, 4, 5) + +// Slicing +subset := slice[1:3] // elemen index 1 hingga 2 + +// Make slice dengan kapasitas +s := make([]int, 5, 10) // length 5, capacity 10 +``` + +Lihat contoh: [examples/06_arrays_slices.go](examples/06_arrays_slices.go) + +## Map + +Map adalah struktur data key-value: + +```go +// Membuat map +ages := make(map[string]int) +ages["Alice"] = 25 +ages["Bob"] = 30 + +// Map literal +scores := map[string]int{ + "Math": 90, + "Physics": 85, +} + +// Mengakses value +age := ages["Alice"] + +// Check key existence +value, exists := ages["Charlie"] +if exists { + fmt.Println(value) +} + +// Delete key +delete(ages, "Bob") + +// Iterate map +for key, value := range scores { + fmt.Printf("%s: %d\n", key, value) +} +``` + +Lihat contoh: [examples/07_maps.go](examples/07_maps.go) + +## Struct + +Struct adalah tipe data komposit yang mengelompokkan field: + +```go +type Person struct { + Name string + Age int + City string +} + +// Membuat instance +p1 := Person{ + Name: "Alice", + Age: 25, + City: "Jakarta", +} + +// Akses field +fmt.Println(p1.Name) + +// Pointer ke struct +p2 := &Person{Name: "Bob", Age: 30} +p2.Age = 31 // otomatis dereference + +// Method pada struct +func (p Person) Introduce() { + fmt.Printf("Hi, I'm %s from %s\n", p.Name, p.City) +} + +// Method dengan pointer receiver +func (p *Person) Birthday() { + p.Age++ +} +``` + +Lihat contoh: [examples/08_structs.go](examples/08_structs.go) + +## Interface + +Interface mendefinisikan set method: + +```go +type Shape interface { + Area() float64 + Perimeter() float64 +} + +type Rectangle struct { + Width float64 + Height float64 +} + +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} + +// Rectangle mengimplementasikan Shape interface +func printShapeInfo(s Shape) { + fmt.Printf("Area: %.2f\n", s.Area()) + fmt.Printf("Perimeter: %.2f\n", s.Perimeter()) +} +``` + +Lihat contoh: [examples/09_interfaces.go](examples/09_interfaces.go) + +## Goroutine dan Channel + +### Goroutine + +Goroutine adalah lightweight thread: + +```go +func sayHello() { + fmt.Println("Hello from goroutine!") +} + +// Menjalankan goroutine +go sayHello() + +// Anonymous goroutine +go func() { + fmt.Println("Anonymous goroutine") +}() +``` + +### Channel + +Channel digunakan untuk komunikasi antar goroutine: + +```go +// Membuat channel +ch := make(chan int) + +// Mengirim data ke channel +go func() { + ch <- 42 +}() + +// Menerima data dari channel +value := <-ch + +// Buffered channel +buffered := make(chan int, 5) + +// Channel dengan range +for value := range ch { + fmt.Println(value) +} + +// Select untuk multiple channel +select { +case msg1 := <-ch1: + fmt.Println(msg1) +case msg2 := <-ch2: + fmt.Println(msg2) +default: + fmt.Println("No message") +} +``` + +Lihat contoh: [examples/10_concurrency.go](examples/10_concurrency.go) + +## Error Handling + +Go menggunakan explicit error handling: + +```go +import "errors" + +// Membuat error +func divide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("division by zero") + } + return a / b, nil +} + +// Menggunakan error +result, err := divide(10, 0) +if err != nil { + fmt.Println("Error:", err) + return +} +fmt.Println("Result:", result) + +// Custom error type +type ValidationError struct { + Field string + Message string +} + +func (e *ValidationError) Error() string { + return fmt.Sprintf("%s: %s", e.Field, e.Message) +} + +// Defer, panic, recover +func safeDivide(a, b int) (result int) { + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from panic:", r) + result = 0 + } + }() + + return a / b // akan panic jika b = 0 +} +``` + +Lihat contoh: [examples/11_errorhandling.go](examples/11_errorhandling.go) + +## Struktur Project + +``` +golang-basic/ +├── README.md +└── examples/ + ├── 01_datatypes.go + ├── 02_variables.go + ├── 03_operators.go + ├── 04_controlflow.go + ├── 05_functions.go + ├── 06_arrays_slices.go + ├── 07_maps.go + ├── 08_structs.go + ├── 09_interfaces.go + ├── 10_concurrency.go + └── 11_errorhandling.go +``` + +## Menjalankan Contoh + +Untuk menjalankan contoh-contoh: + +```bash +# Menjalankan satu file +go run examples/01_datatypes.go + +# Build executable +go build examples/01_datatypes.go + +# Run semua test (jika ada) +go test ./... +``` + +## Resources Tambahan + +- [Official Go Documentation](https://golang.org/doc/) +- [Go by Example](https://gobyexample.com/) +- [A Tour of Go](https://tour.golang.org/) +- [Effective Go](https://golang.org/doc/effective_go) + +## Lisensi + +Repository ini dibuat untuk tujuan pembelajaran. + +--- + +**Selamat belajar Golang! 🚀** \ No newline at end of file diff --git a/examples/01_datatypes.go b/examples/01_datatypes.go new file mode 100644 index 0000000..58e4be1 --- /dev/null +++ b/examples/01_datatypes.go @@ -0,0 +1,64 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Tipe Data di Golang ===\n") + + // Integer + var age int = 25 + var smallNumber int8 = 127 + var bigNumber int64 = 9223372036854775807 + fmt.Printf("Integer: age=%d, smallNumber=%d, bigNumber=%d\n", age, smallNumber, bigNumber) + + // Unsigned Integer + var count uint = 100 + var byteValue uint8 = 255 + fmt.Printf("Unsigned Integer: count=%d, byteValue=%d\n", count, byteValue) + + // Float + var price float32 = 19.99 + var pi float64 = 3.14159265359 + fmt.Printf("Float: price=%.2f, pi=%.10f\n", price, pi) + + // Boolean + var isActive bool = true + var isComplete bool = false + fmt.Printf("Boolean: isActive=%t, isComplete=%t\n", isActive, isComplete) + + // String + var name string = "Golang" + var message string = "Belajar pemrograman Go!" + fmt.Printf("String: name='%s', message='%s'\n", name, message) + + // Byte (alias uint8) + var b byte = 'A' + fmt.Printf("Byte: b=%c (ASCII: %d)\n", b, b) + + // Rune (alias int32) - Unicode code point + var r rune = '世' + fmt.Printf("Rune: r=%c (Unicode: %d)\n", r, r) + + // Complex numbers + var c complex64 = 1 + 2i + var c2 complex128 = 3 + 4i + fmt.Printf("Complex: c=%v, c2=%v\n", c, c2) + + // Zero values (nilai default) + fmt.Println("\n=== Zero Values ===") + var defaultInt int + var defaultFloat float64 + var defaultBool bool + var defaultString string + fmt.Printf("Default int: %d\n", defaultInt) + fmt.Printf("Default float: %f\n", defaultFloat) + fmt.Printf("Default bool: %t\n", defaultBool) + fmt.Printf("Default string: '%s'\n", defaultString) + + // Type conversion + fmt.Println("\n=== Type Conversion ===") + var i int = 42 + var f float64 = float64(i) + var u uint = uint(f) + fmt.Printf("int: %d -> float64: %f -> uint: %d\n", i, f, u) +} diff --git a/examples/02_variables.go b/examples/02_variables.go new file mode 100644 index 0000000..57740ac --- /dev/null +++ b/examples/02_variables.go @@ -0,0 +1,92 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Variabel dan Konstanta ===\n") + + // Deklarasi variabel dengan tipe data eksplisit + var name string = "John Doe" + var age int = 25 + fmt.Printf("Nama: %s, Umur: %d\n", name, age) + + // Type inference (Go menentukan tipe otomatis) + var city = "Jakarta" + var temperature = 28.5 + fmt.Printf("Kota: %s, Suhu: %.1f°C\n", city, temperature) + + // Short declaration (hanya bisa di dalam fungsi) + country := "Indonesia" + population := 273000000 + fmt.Printf("Negara: %s, Populasi: %d\n", country, population) + + // Multiple variable declaration + var x, y int = 10, 20 + fmt.Printf("x: %d, y: %d\n", x, y) + + // Multiple variable dengan tipe berbeda + var ( + firstName string = "Alice" + lastName string = "Smith" + userAge int = 30 + isActive bool = true + ) + fmt.Printf("User: %s %s, Age: %d, Active: %t\n", firstName, lastName, userAge, isActive) + + // Short declaration multiple variables + a, b, c := 1, 2, 3 + fmt.Printf("a: %d, b: %d, c: %d\n", a, b, c) + + // Reassignment + name = "Jane Doe" + age = 28 + fmt.Printf("Updated - Nama: %s, Umur: %d\n", name, age) + + // Konstanta + fmt.Println("\n=== Konstanta ===") + const Pi = 3.14159 + const AppName = "Golang Basic" + const Version = 1.0 + fmt.Printf("App: %s v%.1f\n", AppName, Version) + fmt.Printf("Pi: %f\n", Pi) + + // Konstanta dengan blok + const ( + StatusOK = 200 + StatusNotFound = 404 + StatusServerError = 500 + ) + fmt.Printf("HTTP Status: OK=%d, NotFound=%d, Error=%d\n", StatusOK, StatusNotFound, StatusServerError) + + // Konstanta dengan iota (auto increment) + const ( + Monday = iota + 1 // 1 + Tuesday // 2 + Wednesday // 3 + Thursday // 4 + Friday // 5 + Saturday // 6 + Sunday // 7 + ) + fmt.Printf("Days: Mon=%d, Tue=%d, Wed=%d, Thu=%d, Fri=%d, Sat=%d, Sun=%d\n", + Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday) + + // iota dengan operasi + const ( + _ = iota // 0 (diabaikan) + KB = 1 << (10 * iota) // 1 << 10 = 1024 + MB // 1 << 20 = 1048576 + GB // 1 << 30 = 1073741824 + ) + fmt.Printf("Storage: 1 KB=%d bytes, 1 MB=%d bytes, 1 GB=%d bytes\n", KB, MB, GB) + + // Pointer + fmt.Println("\n=== Pointer ===") + num := 42 + ptr := &num + fmt.Printf("Nilai: %d, Alamat: %p, Pointer: %p, Nilai via Pointer: %d\n", num, &num, ptr, *ptr) + + // Mengubah nilai via pointer + *ptr = 100 + fmt.Printf("Nilai setelah diubah via pointer: %d\n", num) +} diff --git a/examples/03_operators.go b/examples/03_operators.go new file mode 100644 index 0000000..aaf1eee --- /dev/null +++ b/examples/03_operators.go @@ -0,0 +1,86 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Operator di Golang ===\n") + + // Operator Aritmatika + fmt.Println("=== Operator Aritmatika ===") + a, b := 10, 3 + fmt.Printf("a = %d, b = %d\n", a, b) + fmt.Printf("Penjumlahan: %d + %d = %d\n", a, b, a+b) + fmt.Printf("Pengurangan: %d - %d = %d\n", a, b, a-b) + fmt.Printf("Perkalian: %d * %d = %d\n", a, b, a*b) + fmt.Printf("Pembagian: %d / %d = %d\n", a, b, a/b) + fmt.Printf("Modulus: %d %% %d = %d\n", a, b, a%b) + + // Increment dan Decrement + counter := 5 + fmt.Printf("\nCounter awal: %d\n", counter) + counter++ + fmt.Printf("Setelah counter++: %d\n", counter) + counter-- + fmt.Printf("Setelah counter--: %d\n", counter) + + // Operator Assignment + fmt.Println("\n=== Operator Assignment ===") + x := 10 + fmt.Printf("x awal: %d\n", x) + x += 5 + fmt.Printf("x += 5: %d\n", x) + x -= 3 + fmt.Printf("x -= 3: %d\n", x) + x *= 2 + fmt.Printf("x *= 2: %d\n", x) + x /= 4 + fmt.Printf("x /= 4: %d\n", x) + x %= 3 + fmt.Printf("x %%= 3: %d\n", x) + + // Operator Perbandingan + fmt.Println("\n=== Operator Perbandingan ===") + num1, num2 := 15, 20 + fmt.Printf("num1 = %d, num2 = %d\n", num1, num2) + fmt.Printf("num1 == num2: %t\n", num1 == num2) + fmt.Printf("num1 != num2: %t\n", num1 != num2) + fmt.Printf("num1 < num2: %t\n", num1 < num2) + fmt.Printf("num1 > num2: %t\n", num1 > num2) + fmt.Printf("num1 <= num2: %t\n", num1 <= num2) + fmt.Printf("num1 >= num2: %t\n", num1 >= num2) + + // Operator Logika + fmt.Println("\n=== Operator Logika ===") + isAdult := true + hasLicense := false + fmt.Printf("isAdult = %t, hasLicense = %t\n", isAdult, hasLicense) + fmt.Printf("isAdult && hasLicense: %t\n", isAdult && hasLicense) + fmt.Printf("isAdult || hasLicense: %t\n", isAdult || hasLicense) + fmt.Printf("!isAdult: %t\n", !isAdult) + fmt.Printf("!hasLicense: %t\n", !hasLicense) + + // Operator Bitwise + fmt.Println("\n=== Operator Bitwise ===") + p, q := 12, 10 // 12 = 1100, 10 = 1010 dalam binary + fmt.Printf("p = %d (binary: %b), q = %d (binary: %b)\n", p, p, q, q) + fmt.Printf("p & q (AND): %d (binary: %b)\n", p&q, p&q) + fmt.Printf("p | q (OR): %d (binary: %b)\n", p|q, p|q) + fmt.Printf("p ^ q (XOR): %d (binary: %b)\n", p^q, p^q) + fmt.Printf("p &^ q (AND NOT): %d (binary: %b)\n", p&^q, p&^q) + fmt.Printf("p << 1 (Left Shift): %d (binary: %b)\n", p<<1, p<<1) + fmt.Printf("p >> 1 (Right Shift): %d (binary: %b)\n", p>>1, p>>1) + + // Operator Precedence (urutan operasi) + fmt.Println("\n=== Operator Precedence ===") + result := 2 + 3*4 + fmt.Printf("2 + 3 * 4 = %d (perkalian dulu)\n", result) + result = (2 + 3) * 4 + fmt.Printf("(2 + 3) * 4 = %d (kurung dulu)\n", result) + + // Complex expression + age := 25 + hasID := true + canVote := age >= 17 && hasID + fmt.Printf("\nUmur: %d, Punya ID: %t\n", age, hasID) + fmt.Printf("Bisa voting: %t\n", canVote) +} diff --git a/examples/04_controlflow.go b/examples/04_controlflow.go new file mode 100644 index 0000000..dfedb20 --- /dev/null +++ b/examples/04_controlflow.go @@ -0,0 +1,187 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Kontrol Alur (Control Flow) ===\n") + + // IF Statement + fmt.Println("=== IF Statement ===") + age := 20 + if age >= 18 { + fmt.Printf("Umur %d: Dewasa\n", age) + } else { + fmt.Printf("Umur %d: Anak-anak\n", age) + } + + // IF dengan else if + score := 85 + if score >= 90 { + fmt.Println("Grade: A") + } else if score >= 80 { + fmt.Println("Grade: B") + } else if score >= 70 { + fmt.Println("Grade: C") + } else if score >= 60 { + fmt.Println("Grade: D") + } else { + fmt.Println("Grade: F") + } + + // IF dengan short statement + if value := 100; value > 50 { + fmt.Printf("Nilai %d lebih besar dari 50\n", value) + } + + // SWITCH Statement + fmt.Println("\n=== SWITCH Statement ===") + day := "Rabu" + switch day { + case "Senin": + fmt.Println("Awal minggu") + case "Selasa", "Rabu", "Kamis": + fmt.Println("Pertengahan minggu") + case "Jumat": + fmt.Println("Akhir minggu kerja") + case "Sabtu", "Minggu": + fmt.Println("Akhir pekan") + default: + fmt.Println("Hari tidak valid") + } + + // Switch tanpa kondisi (seperti if-else chain) + hour := 14 + switch { + case hour < 12: + fmt.Println("Selamat pagi") + case hour < 17: + fmt.Println("Selamat siang") + case hour < 21: + fmt.Println("Selamat sore") + default: + fmt.Println("Selamat malam") + } + + // Switch dengan short statement + switch time := "malam"; time { + case "pagi": + fmt.Println("Sarapan") + case "siang": + fmt.Println("Makan siang") + case "malam": + fmt.Println("Makan malam") + } + + // FOR Loop + fmt.Println("\n=== FOR Loop ===") + + // For loop standar + fmt.Println("Counting 1-5:") + for i := 1; i <= 5; i++ { + fmt.Printf("%d ", i) + } + fmt.Println() + + // For sebagai while loop + count := 0 + fmt.Println("\nWhile-style loop:") + for count < 3 { + fmt.Printf("Count: %d\n", count) + count++ + } + + // Infinite loop dengan break + fmt.Println("\nInfinite loop dengan break:") + n := 0 + for { + if n >= 3 { + break + } + fmt.Printf("n = %d\n", n) + n++ + } + + // Continue statement + fmt.Println("\nContinue - skip genap:") + for i := 1; i <= 5; i++ { + if i%2 == 0 { + continue + } + fmt.Printf("%d ", i) + } + fmt.Println() + + // Range loop dengan array + fmt.Println("\n=== Range Loop ===") + numbers := []int{10, 20, 30, 40, 50} + fmt.Println("Iterasi dengan index dan value:") + for index, value := range numbers { + fmt.Printf("Index %d: Value %d\n", index, value) + } + + // Range hanya index + fmt.Println("\nHanya index:") + for index := range numbers { + fmt.Printf("%d ", index) + } + fmt.Println() + + // Range hanya value (skip index dengan _) + fmt.Println("\nHanya value:") + for _, value := range numbers { + fmt.Printf("%d ", value) + } + fmt.Println() + + // Range dengan string + fmt.Println("\nRange dengan string:") + text := "Hello" + for index, char := range text { + fmt.Printf("Index %d: %c\n", index, char) + } + + // Range dengan map + fmt.Println("\nRange dengan map:") + fruits := map[string]int{ + "apel": 5, + "pisang": 3, + "jeruk": 7, + } + for name, quantity := range fruits { + fmt.Printf("%s: %d\n", name, quantity) + } + + // Nested loops + fmt.Println("\n=== Nested Loops ===") + fmt.Println("Tabel perkalian 3x3:") + for i := 1; i <= 3; i++ { + for j := 1; j <= 3; j++ { + fmt.Printf("%d x %d = %d\t", i, j, i*j) + } + fmt.Println() + } + + // Label dan break ke label + fmt.Println("\n=== Label dengan Break ===") +outer: + for i := 0; i < 3; i++ { + for j := 0; j < 3; j++ { + if i == 1 && j == 1 { + fmt.Println("Breaking outer loop at i=1, j=1") + break outer + } + fmt.Printf("i=%d, j=%d\n", i, j) + } + } + + // Goto (jarang digunakan, tapi tersedia) + fmt.Println("\n=== GOTO Statement ===") + x := 0 +loop: + fmt.Printf("x = %d\n", x) + x++ + if x < 3 { + goto loop + } + fmt.Println("Done with goto") +} diff --git a/examples/05_functions.go b/examples/05_functions.go new file mode 100644 index 0000000..3881a17 --- /dev/null +++ b/examples/05_functions.go @@ -0,0 +1,180 @@ +package main + +import ( + "fmt" + "errors" +) + +func main() { + fmt.Println("=== Contoh Fungsi di Golang ===\n") + + // Fungsi sederhana tanpa parameter dan return + greet() + + // Fungsi dengan parameter + greetPerson("Alice") + + // Fungsi dengan return value + sum := add(5, 3) + fmt.Printf("5 + 3 = %d\n", sum) + + // Fungsi dengan multiple parameters + fullName := createFullName("John", "Doe") + fmt.Printf("Full name: %s\n", fullName) + + // Fungsi dengan multiple return values + result, remainder := divide(17, 5) + fmt.Printf("17 / 5 = %d dengan sisa %d\n", result, remainder) + + // Fungsi dengan error handling + quotient, err := safeDivide(10, 2) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Printf("10 / 2 = %.2f\n", quotient) + } + + quotient, err = safeDivide(10, 0) + if err != nil { + fmt.Println("Error:", err) + } + + // Named return values + s, p := calculate(4, 5) + fmt.Printf("Sum: %d, Product: %d\n", s, p) + + // Variadic function + total := sumNumbers(1, 2, 3, 4, 5) + fmt.Printf("Sum of 1,2,3,4,5 = %d\n", total) + + // Anonymous function + fmt.Println("\n=== Anonymous Function ===") + result = func(a, b int) int { + return a * b + }(6, 7) + fmt.Printf("6 * 7 = %d\n", result) + + // Function sebagai variable + multiply := func(a, b int) int { + return a * b + } + fmt.Printf("multiply(3, 4) = %d\n", multiply(3, 4)) + + // Function sebagai parameter + fmt.Println("\n=== Function sebagai Parameter ===") + numbers := []int{1, 2, 3, 4, 5} + applyOperation(numbers, func(n int) int { + return n * 2 + }) + + // Closure + fmt.Println("\n=== Closure ===") + counter := makeCounter() + fmt.Println("Counter:", counter()) // 1 + fmt.Println("Counter:", counter()) // 2 + fmt.Println("Counter:", counter()) // 3 + + // Recursive function + fmt.Println("\n=== Recursive Function ===") + fmt.Printf("Factorial of 5: %d\n", factorial(5)) + fmt.Printf("Fibonacci(7): %d\n", fibonacci(7)) + + // Defer + fmt.Println("\n=== Defer ===") + deferExample() +} + +// Fungsi sederhana +func greet() { + fmt.Println("Hello, World!") +} + +// Fungsi dengan parameter +func greetPerson(name string) { + fmt.Printf("Hello, %s!\n", name) +} + +// Fungsi dengan return value +func add(a int, b int) int { + return a + b +} + +// Parameter dengan tipe yang sama bisa digabung +func createFullName(firstName, lastName string) string { + return firstName + " " + lastName +} + +// Multiple return values +func divide(a, b int) (int, int) { + quotient := a / b + remainder := a % b + return quotient, remainder +} + +// Return dengan error handling +func safeDivide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("division by zero") + } + return a / b, nil +} + +// Named return values +func calculate(a, b int) (sum int, product int) { + sum = a + b + product = a * b + return // naked return +} + +// Variadic function (parameter dengan jumlah variable) +func sumNumbers(numbers ...int) int { + total := 0 + for _, num := range numbers { + total += num + } + return total +} + +// Function yang menerima function sebagai parameter +func applyOperation(numbers []int, operation func(int) int) { + fmt.Print("Apply operation: ") + for _, num := range numbers { + fmt.Printf("%d ", operation(num)) + } + fmt.Println() +} + +// Closure - function yang mengembalikan function +func makeCounter() func() int { + count := 0 + return func() int { + count++ + return count + } +} + +// Recursive function - Factorial +func factorial(n int) int { + if n <= 1 { + return 1 + } + return n * factorial(n-1) +} + +// Recursive function - Fibonacci +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +// Defer example +func deferExample() { + fmt.Println("Start") + defer fmt.Println("Deferred 1") // dijalankan paling akhir (LIFO) + defer fmt.Println("Deferred 2") + defer fmt.Println("Deferred 3") + fmt.Println("End") + // Output: Start, End, Deferred 3, Deferred 2, Deferred 1 +} diff --git a/examples/06_arrays_slices.go b/examples/06_arrays_slices.go new file mode 100644 index 0000000..9f1e994 --- /dev/null +++ b/examples/06_arrays_slices.go @@ -0,0 +1,163 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Array dan Slice ===\n") + + // ARRAY + fmt.Println("=== ARRAY ===") + + // Deklarasi array dengan ukuran tetap + var numbers [5]int + numbers[0] = 10 + numbers[1] = 20 + numbers[2] = 30 + numbers[3] = 40 + numbers[4] = 50 + fmt.Printf("Array numbers: %v\n", numbers) + + // Inisialisasi array dengan nilai + fruits := [3]string{"Apple", "Banana", "Orange"} + fmt.Printf("Array fruits: %v\n", fruits) + + // Array dengan ukuran otomatis + colors := [...]string{"Red", "Green", "Blue", "Yellow"} + fmt.Printf("Array colors: %v (length: %d)\n", colors, len(colors)) + + // Akses element array + fmt.Printf("First fruit: %s\n", fruits[0]) + fmt.Printf("Last fruit: %s\n", fruits[len(fruits)-1]) + + // Iterasi array + fmt.Print("Iterate colors: ") + for i := 0; i < len(colors); i++ { + fmt.Printf("%s ", colors[i]) + } + fmt.Println() + + // Iterasi dengan range + fmt.Println("Fruits dengan range:") + for index, fruit := range fruits { + fmt.Printf(" Index %d: %s\n", index, fruit) + } + + // Multi-dimensional array + var matrix [3][3]int + matrix[0][0] = 1 + matrix[1][1] = 5 + matrix[2][2] = 9 + fmt.Printf("Matrix: %v\n", matrix) + + // SLICE + fmt.Println("\n=== SLICE ===") + + // Membuat slice + var slice []int + fmt.Printf("Empty slice: %v (len: %d, cap: %d)\n", slice, len(slice), cap(slice)) + + // Slice literal + names := []string{"Alice", "Bob", "Charlie"} + fmt.Printf("Slice names: %v (len: %d, cap: %d)\n", names, len(names), cap(names)) + + // Append ke slice + names = append(names, "David") + fmt.Printf("After append: %v (len: %d, cap: %d)\n", names, len(names), cap(names)) + + // Append multiple values + names = append(names, "Eve", "Frank") + fmt.Printf("After append multiple: %v (len: %d, cap: %d)\n", names, len(names), cap(names)) + + // Make slice dengan capacity + scores := make([]int, 5, 10) // length 5, capacity 10 + fmt.Printf("Slice with make: %v (len: %d, cap: %d)\n", scores, len(scores), cap(scores)) + + // Set values + for i := 0; i < len(scores); i++ { + scores[i] = (i + 1) * 10 + } + fmt.Printf("Scores after set: %v\n", scores) + + // Slicing operation + fmt.Println("\n=== Slicing Operation ===") + nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + fmt.Printf("Original: %v\n", nums) + fmt.Printf("nums[2:5]: %v\n", nums[2:5]) // index 2 sampai 4 + fmt.Printf("nums[:4]: %v\n", nums[:4]) // dari awal sampai index 3 + fmt.Printf("nums[6:]: %v\n", nums[6:]) // dari index 6 sampai akhir + fmt.Printf("nums[:]: %v\n", nums[:]) // semua elemen + fmt.Printf("nums[1:8:9]: %v (cap: %d)\n", nums[1:8:9], cap(nums[1:8:9])) // [low:high:max] + + // Copy slice + fmt.Println("\n=== Copy Slice ===") + source := []int{1, 2, 3, 4, 5} + destination := make([]int, len(source)) + copied := copy(destination, source) + fmt.Printf("Source: %v\n", source) + fmt.Printf("Destination: %v\n", destination) + fmt.Printf("Elements copied: %d\n", copied) + + // Modifikasi copy tidak mempengaruhi original + destination[0] = 100 + fmt.Printf("After modify destination[0]: source=%v, dest=%v\n", source, destination) + + // Slice of slices + fmt.Println("\n=== 2D Slice ===") + matrix2D := [][]int{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + } + fmt.Println("2D Matrix:") + for i, row := range matrix2D { + fmt.Printf("Row %d: %v\n", i, row) + } + + // Remove element dari slice + fmt.Println("\n=== Remove Element ===") + items := []string{"a", "b", "c", "d", "e"} + fmt.Printf("Original: %v\n", items) + + // Remove index 2 (element "c") + indexToRemove := 2 + items = append(items[:indexToRemove], items[indexToRemove+1:]...) + fmt.Printf("After remove index 2: %v\n", items) + + // Insert element + fmt.Println("\n=== Insert Element ===") + letters := []string{"a", "b", "d", "e"} + fmt.Printf("Original: %v\n", letters) + + // Insert "c" at index 2 + insertIndex := 2 + letters = append(letters[:insertIndex], append([]string{"c"}, letters[insertIndex:]...)...) + fmt.Printf("After insert 'c' at index 2: %v\n", letters) + + // Filter slice + fmt.Println("\n=== Filter Slice ===") + allNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + var evenNumbers []int + for _, num := range allNumbers { + if num%2 == 0 { + evenNumbers = append(evenNumbers, num) + } + } + fmt.Printf("All: %v\n", allNumbers) + fmt.Printf("Even: %v\n", evenNumbers) + + // Nil slice vs empty slice + fmt.Println("\n=== Nil vs Empty Slice ===") + var nilSlice []int + emptySlice := []int{} + fmt.Printf("Nil slice: %v (len: %d, cap: %d, is nil: %t)\n", nilSlice, len(nilSlice), cap(nilSlice), nilSlice == nil) + fmt.Printf("Empty slice: %v (len: %d, cap: %d, is nil: %t)\n", emptySlice, len(emptySlice), cap(emptySlice), emptySlice == nil) + + // Append slices together + fmt.Println("\n=== Append Slices ===") + slice1 := []int{1, 2, 3} + slice2 := []int{4, 5, 6} + combined := append(slice1, slice2...) + fmt.Printf("Slice1: %v\n", slice1) + fmt.Printf("Slice2: %v\n", slice2) + fmt.Printf("Combined: %v\n", combined) +} diff --git a/examples/07_maps.go b/examples/07_maps.go new file mode 100644 index 0000000..51bd792 --- /dev/null +++ b/examples/07_maps.go @@ -0,0 +1,195 @@ +package main + +import "fmt" + +func main() { + fmt.Println("=== Contoh Map di Golang ===\n") + + // Membuat map dengan make + fmt.Println("=== Membuat Map ===") + ages := make(map[string]int) + ages["Alice"] = 25 + ages["Bob"] = 30 + ages["Charlie"] = 35 + fmt.Printf("Ages: %v\n", ages) + + // Map literal + scores := map[string]int{ + "Math": 90, + "Physics": 85, + "Chemistry": 88, + } + fmt.Printf("Scores: %v\n", scores) + + // Map dengan value yang lebih kompleks + students := map[string]map[string]interface{}{ + "Alice": { + "age": 20, + "grade": "A", + }, + "Bob": { + "age": 22, + "grade": "B", + }, + } + fmt.Printf("Students: %v\n", students) + + // Akses value + fmt.Println("\n=== Akses Value ===") + aliceAge := ages["Alice"] + fmt.Printf("Alice's age: %d\n", aliceAge) + + mathScore := scores["Math"] + fmt.Printf("Math score: %d\n", mathScore) + + // Check key existence + fmt.Println("\n=== Check Key Existence ===") + age, exists := ages["David"] + if exists { + fmt.Printf("David's age: %d\n", age) + } else { + fmt.Println("David not found in ages map") + } + + // Menggunakan value tanpa check (return zero value jika tidak ada) + unknownAge := ages["Unknown"] + fmt.Printf("Unknown age: %d (zero value)\n", unknownAge) + + // Update value + fmt.Println("\n=== Update Value ===") + fmt.Printf("Bob's age before: %d\n", ages["Bob"]) + ages["Bob"] = 31 + fmt.Printf("Bob's age after: %d\n", ages["Bob"]) + + // Delete key + fmt.Println("\n=== Delete Key ===") + fmt.Printf("Before delete: %v\n", ages) + delete(ages, "Charlie") + fmt.Printf("After delete Charlie: %v\n", ages) + + // Iterate map + fmt.Println("\n=== Iterate Map ===") + fmt.Println("Scores:") + for subject, score := range scores { + fmt.Printf(" %s: %d\n", subject, score) + } + + // Iterate hanya keys + fmt.Println("\nSubjects (keys only):") + for subject := range scores { + fmt.Printf(" %s\n", subject) + } + + // Map length + fmt.Printf("\nNumber of students: %d\n", len(ages)) + fmt.Printf("Number of subjects: %d\n", len(scores)) + + // Map of slices + fmt.Println("\n=== Map of Slices ===") + classes := map[string][]string{ + "Math": {"Alice", "Bob", "Charlie"}, + "Physics": {"Alice", "David"}, + "Chemistry": {"Bob", "Eve"}, + } + fmt.Println("Classes:") + for subject, students := range classes { + fmt.Printf(" %s: %v\n", subject, students) + } + + // Nested maps + fmt.Println("\n=== Nested Maps ===") + userProfiles := map[string]map[string]string{ + "alice": { + "email": "alice@example.com", + "city": "Jakarta", + }, + "bob": { + "email": "bob@example.com", + "city": "Bandung", + }, + } + fmt.Println("User Profiles:") + for username, profile := range userProfiles { + fmt.Printf(" User: %s\n", username) + for key, value := range profile { + fmt.Printf(" %s: %s\n", key, value) + } + } + + // Map dengan struct sebagai value + fmt.Println("\n=== Map with Struct Values ===") + type Person struct { + Name string + Age int + City string + } + + people := map[int]Person{ + 1: {Name: "Alice", Age: 25, City: "Jakarta"}, + 2: {Name: "Bob", Age: 30, City: "Bandung"}, + 3: {Name: "Charlie", Age: 35, City: "Surabaya"}, + } + + fmt.Println("People:") + for id, person := range people { + fmt.Printf(" ID %d: %s (%d years) from %s\n", id, person.Name, person.Age, person.City) + } + + // Check and add if not exists + fmt.Println("\n=== Check and Add ===") + inventory := map[string]int{ + "apple": 10, + "banana": 5, + } + + // Add orange if not exists + if _, exists := inventory["orange"]; !exists { + inventory["orange"] = 7 + fmt.Println("Added orange to inventory") + } + fmt.Printf("Inventory: %v\n", inventory) + + // Increment value + fmt.Println("\n=== Increment Value ===") + counter := make(map[string]int) + words := []string{"hello", "world", "hello", "golang", "world", "hello"} + + for _, word := range words { + counter[word]++ + } + + fmt.Println("Word counter:") + for word, count := range counter { + fmt.Printf(" %s: %d\n", word, count) + } + + // Clear all entries (Go doesn't have built-in clear for maps before Go 1.21) + fmt.Println("\n=== Clear Map ===") + temp := map[string]int{"a": 1, "b": 2, "c": 3} + fmt.Printf("Before clear: %v\n", temp) + + // Method 1: Assign new empty map + temp = make(map[string]int) + fmt.Printf("After clear: %v\n", temp) + + // Method 2: Delete all keys + temp2 := map[string]int{"x": 1, "y": 2, "z": 3} + fmt.Printf("Before delete all: %v\n", temp2) + for key := range temp2 { + delete(temp2, key) + } + fmt.Printf("After delete all: %v\n", temp2) + + // Nil map vs empty map + fmt.Println("\n=== Nil Map vs Empty Map ===") + var nilMap map[string]int + emptyMap := make(map[string]int) + + fmt.Printf("Nil map: %v (len: %d, is nil: %t)\n", nilMap, len(nilMap), nilMap == nil) + fmt.Printf("Empty map: %v (len: %d, is nil: %t)\n", emptyMap, len(emptyMap), emptyMap == nil) + + // Writing to nil map will panic! + // nilMap["key"] = 1 // This would cause panic + emptyMap["key"] = 1 // This is OK + fmt.Printf("After adding to empty map: %v\n", emptyMap) +} diff --git a/examples/08_structs.go b/examples/08_structs.go new file mode 100644 index 0000000..1c39628 --- /dev/null +++ b/examples/08_structs.go @@ -0,0 +1,230 @@ +package main + +import "fmt" + +// Definisi struct +type Person struct { + Name string + Age int + City string +} + +// Struct dengan field tags +type User struct { + ID int `json:"id"` + Username string `json:"username"` + Email string `json:"email"` +} + +// Nested struct +type Address struct { + Street string + City string + ZipCode string +} + +type Employee struct { + Name string + Age int + Address Address +} + +// Embedded struct +type Contact struct { + Phone string + Email string +} + +type Customer struct { + Name string + Contact // embedded +} + +func main() { + fmt.Println("=== Contoh Struct di Golang ===\n") + + // Membuat instance struct + fmt.Println("=== Membuat Struct ===") + + // Cara 1: Dengan field names + person1 := Person{ + Name: "Alice", + Age: 25, + City: "Jakarta", + } + fmt.Printf("Person1: %+v\n", person1) + + // Cara 2: Tanpa field names (harus urut) + person2 := Person{"Bob", 30, "Bandung"} + fmt.Printf("Person2: %+v\n", person2) + + // Cara 3: Partial initialization + person3 := Person{Name: "Charlie"} + fmt.Printf("Person3: %+v\n", person3) // Age dan City akan jadi zero value + + // Cara 4: Zero value struct + var person4 Person + fmt.Printf("Person4 (zero value): %+v\n", person4) + + // Akses dan modifikasi field + fmt.Println("\n=== Akses Field ===") + fmt.Printf("Name: %s\n", person1.Name) + fmt.Printf("Age: %d\n", person1.Age) + fmt.Printf("City: %s\n", person1.City) + + person1.Age = 26 + fmt.Printf("Updated age: %d\n", person1.Age) + + // Pointer ke struct + fmt.Println("\n=== Pointer ke Struct ===") + person5 := &Person{ + Name: "David", + Age: 35, + City: "Surabaya", + } + fmt.Printf("Person5: %+v\n", person5) + + // Go otomatis dereference pointer + person5.Age = 36 + fmt.Printf("Updated via pointer: %+v\n", person5) + + // Anonymous struct + fmt.Println("\n=== Anonymous Struct ===") + car := struct { + Brand string + Year int + Color string + }{ + Brand: "Toyota", + Year: 2023, + Color: "Red", + } + fmt.Printf("Car: %+v\n", car) + + // Struct comparison + fmt.Println("\n=== Struct Comparison ===") + p1 := Person{Name: "Alice", Age: 25, City: "Jakarta"} + p2 := Person{Name: "Alice", Age: 25, City: "Jakarta"} + p3 := Person{Name: "Bob", Age: 30, City: "Bandung"} + + fmt.Printf("p1 == p2: %t\n", p1 == p2) + fmt.Printf("p1 == p3: %t\n", p1 == p3) + + // Nested struct + fmt.Println("\n=== Nested Struct ===") + emp := Employee{ + Name: "John Doe", + Age: 28, + Address: Address{ + Street: "Jl. Sudirman No. 123", + City: "Jakarta", + ZipCode: "12345", + }, + } + fmt.Printf("Employee: %+v\n", emp) + fmt.Printf("Employee city: %s\n", emp.Address.City) + + // Embedded struct + fmt.Println("\n=== Embedded Struct ===") + customer := Customer{ + Name: "Jane Smith", + Contact: Contact{ + Phone: "08123456789", + Email: "jane@example.com", + }, + } + fmt.Printf("Customer: %+v\n", customer) + // Bisa akses field embedded langsung + fmt.Printf("Customer phone: %s\n", customer.Phone) + fmt.Printf("Customer email: %s\n", customer.Email) + + // Struct methods + fmt.Println("\n=== Struct Methods ===") + alice := Person{Name: "Alice", Age: 25, City: "Jakarta"} + alice.Introduce() + alice.HaveBirthday() + alice.Introduce() + + // Method dengan pointer receiver + fmt.Println("\nUsing pointer receiver:") + bob := &Person{Name: "Bob", Age: 30, City: "Bandung"} + bob.UpdateCity("Surabaya") + fmt.Printf("Updated person: %+v\n", bob) + + // Slice of structs + fmt.Println("\n=== Slice of Structs ===") + people := []Person{ + {Name: "Alice", Age: 25, City: "Jakarta"}, + {Name: "Bob", Age: 30, City: "Bandung"}, + {Name: "Charlie", Age: 35, City: "Surabaya"}, + } + + fmt.Println("People:") + for i, person := range people { + fmt.Printf(" %d: %s (%d) from %s\n", i+1, person.Name, person.Age, person.City) + } + + // Map of structs + fmt.Println("\n=== Map of Structs ===") + userMap := map[int]User{ + 1: {ID: 1, Username: "alice", Email: "alice@example.com"}, + 2: {ID: 2, Username: "bob", Email: "bob@example.com"}, + } + + fmt.Println("Users:") + for id, user := range userMap { + fmt.Printf(" ID %d: %s (%s)\n", id, user.Username, user.Email) + } + + // Constructor pattern + fmt.Println("\n=== Constructor Pattern ===") + newPerson := NewPerson("Eve", 28, "Medan") + fmt.Printf("New person: %+v\n", newPerson) + + // Struct with methods for calculations + fmt.Println("\n=== Struct with Calculations ===") + rect := Rectangle{Width: 10, Height: 5} + fmt.Printf("Rectangle: %+v\n", rect) + fmt.Printf("Area: %.2f\n", rect.Area()) + fmt.Printf("Perimeter: %.2f\n", rect.Perimeter()) +} + +// Method dengan value receiver +func (p Person) Introduce() { + fmt.Printf("Hi, I'm %s, %d years old from %s\n", p.Name, p.Age, p.City) +} + +// Method yang memodifikasi struct (tetapi tidak permanen dengan value receiver) +func (p Person) HaveBirthday() { + p.Age++ // ini tidak akan mengubah original struct + fmt.Printf("Happy birthday! New age: %d (not permanent)\n", p.Age) +} + +// Method dengan pointer receiver (bisa modifikasi struct) +func (p *Person) UpdateCity(newCity string) { + p.City = newCity + fmt.Printf("City updated to: %s\n", p.City) +} + +// Constructor function +func NewPerson(name string, age int, city string) *Person { + return &Person{ + Name: name, + Age: age, + City: city, + } +} + +// Struct untuk contoh calculation +type Rectangle struct { + Width float64 + Height float64 +} + +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} diff --git a/examples/09_interfaces.go b/examples/09_interfaces.go new file mode 100644 index 0000000..753ecff --- /dev/null +++ b/examples/09_interfaces.go @@ -0,0 +1,280 @@ +package main + +import ( + "fmt" + "math" +) + +// Interface mendefinisikan kontrak (set of methods) +type Shape interface { + Area() float64 + Perimeter() float64 +} + +// Struct Rectangle +type Rectangle struct { + Width float64 + Height float64 +} + +// Rectangle mengimplementasikan Shape interface +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} + +// Struct Circle +type Circle struct { + Radius float64 +} + +// Circle mengimplementasikan Shape interface +func (c Circle) Area() float64 { + return math.Pi * c.Radius * c.Radius +} + +func (c Circle) Perimeter() float64 { + return 2 * math.Pi * c.Radius +} + +// Interface untuk animal +type Animal interface { + Speak() string + Move() string +} + +type Dog struct { + Name string +} + +func (d Dog) Speak() string { + return "Woof!" +} + +func (d Dog) Move() string { + return "Running" +} + +type Cat struct { + Name string +} + +func (c Cat) Speak() string { + return "Meow!" +} + +func (c Cat) Move() string { + return "Walking" +} + +// Empty interface +type Any interface{} + +// Interface composition +type Reader interface { + Read() string +} + +type Writer interface { + Write(data string) +} + +// ReadWriter adalah komposisi dari Reader dan Writer +type ReadWriter interface { + Reader + Writer +} + +type File struct { + Content string +} + +func (f File) Read() string { + return f.Content +} + +func (f *File) Write(data string) { + f.Content = data +} + +func main() { + fmt.Println("=== Contoh Interface di Golang ===\n") + + // Menggunakan interface + fmt.Println("=== Shape Interface ===") + rect := Rectangle{Width: 10, Height: 5} + circle := Circle{Radius: 7} + + printShapeInfo(rect) + printShapeInfo(circle) + + // Slice of interface + fmt.Println("\n=== Slice of Interface ===") + shapes := []Shape{ + Rectangle{Width: 5, Height: 3}, + Circle{Radius: 4}, + Rectangle{Width: 8, Height: 6}, + } + + totalArea := 0.0 + for i, shape := range shapes { + area := shape.Area() + fmt.Printf("Shape %d - Area: %.2f, Perimeter: %.2f\n", i+1, area, shape.Perimeter()) + totalArea += area + } + fmt.Printf("Total area: %.2f\n", totalArea) + + // Animal interface + fmt.Println("\n=== Animal Interface ===") + dog := Dog{Name: "Buddy"} + cat := Cat{Name: "Whiskers"} + + animals := []Animal{dog, cat} + for _, animal := range animals { + fmt.Printf("Animal speaks: %s, moves by %s\n", animal.Speak(), animal.Move()) + } + + // Type assertion + fmt.Println("\n=== Type Assertion ===") + var shape Shape = Rectangle{Width: 10, Height: 5} + + // Type assertion dengan check + if rect, ok := shape.(Rectangle); ok { + fmt.Printf("It's a rectangle with width: %.2f and height: %.2f\n", rect.Width, rect.Height) + } + + // Type assertion tanpa check (bisa panic jika salah) + rectangle := shape.(Rectangle) + fmt.Printf("Rectangle: %+v\n", rectangle) + + // Type switch + fmt.Println("\n=== Type Switch ===") + describeShape(Rectangle{Width: 5, Height: 3}) + describeShape(Circle{Radius: 4}) + describeShape("This is a string") + + // Empty interface + fmt.Println("\n=== Empty Interface ===") + var anything interface{} + + anything = 42 + fmt.Printf("Value: %v, Type: %T\n", anything, anything) + + anything = "Hello" + fmt.Printf("Value: %v, Type: %T\n", anything, anything) + + anything = true + fmt.Printf("Value: %v, Type: %T\n", anything, anything) + + anything = Rectangle{Width: 10, Height: 5} + fmt.Printf("Value: %v, Type: %T\n", anything, anything) + + // Function dengan empty interface parameter + fmt.Println("\n=== Function with Empty Interface ===") + printAny(42) + printAny("Golang") + printAny(3.14) + printAny([]int{1, 2, 3}) + + // Interface composition + fmt.Println("\n=== Interface Composition ===") + file := &File{Content: "Initial content"} + fmt.Printf("Read: %s\n", file.Read()) + file.Write("New content") + fmt.Printf("Read after write: %s\n", file.Read()) + + // Interface values + fmt.Println("\n=== Interface Values ===") + var animal Animal + fmt.Printf("Initial - Value: %v, Type: %T\n", animal, animal) + + animal = Dog{Name: "Rex"} + fmt.Printf("After assignment - Value: %v, Type: %T\n", animal, animal) + fmt.Printf("Speaks: %s\n", animal.Speak()) + + // Nil interface vs interface with nil value + fmt.Println("\n=== Nil Interface ===") + var nilInterface Animal + fmt.Printf("Nil interface: %v (is nil: %t)\n", nilInterface, nilInterface == nil) + + var nilDog *Dog + var interfaceWithNil Animal = nilDog + fmt.Printf("Interface with nil value: %v (is nil: %t)\n", interfaceWithNil, interfaceWithNil == nil) + + // Polymorphism + fmt.Println("\n=== Polymorphism ===") + processAnimals([]Animal{ + Dog{Name: "Max"}, + Cat{Name: "Luna"}, + Dog{Name: "Charlie"}, + }) + + // Interface method with different receivers + fmt.Println("\n=== Different Receivers ===") + counter := &Counter{Value: 0} + demonstrateCounter(counter) +} + +// Function yang menerima interface +func printShapeInfo(s Shape) { + fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter()) +} + +// Type switch +func describeShape(i interface{}) { + switch v := i.(type) { + case Rectangle: + fmt.Printf("Rectangle with area: %.2f\n", v.Area()) + case Circle: + fmt.Printf("Circle with area: %.2f\n", v.Area()) + case string: + fmt.Printf("String: %s\n", v) + case int: + fmt.Printf("Integer: %d\n", v) + default: + fmt.Printf("Unknown type: %T\n", v) + } +} + +// Function dengan empty interface +func printAny(value interface{}) { + fmt.Printf("Value: %v, Type: %T\n", value, value) +} + +// Polymorphism example +func processAnimals(animals []Animal) { + for i, animal := range animals { + fmt.Printf("Animal %d: %s - %s\n", i+1, animal.Speak(), animal.Move()) + } +} + +// Counter untuk demonstrasi method dengan pointer receiver +type Counter struct { + Value int +} + +func (c *Counter) Increment() { + c.Value++ +} + +func (c Counter) GetValue() int { + return c.Value +} + +type Incrementer interface { + Increment() +} + +func demonstrateCounter(inc Incrementer) { + fmt.Println("Demonstrating counter:") + for i := 0; i < 3; i++ { + inc.Increment() + // inc harus berupa pointer karena Increment() memiliki pointer receiver + if counter, ok := inc.(*Counter); ok { + fmt.Printf(" Counter value: %d\n", counter.Value) + } + } +} diff --git a/examples/10_concurrency.go b/examples/10_concurrency.go new file mode 100644 index 0000000..3aa1db7 --- /dev/null +++ b/examples/10_concurrency.go @@ -0,0 +1,289 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +func main() { + fmt.Println("=== Contoh Concurrency: Goroutine dan Channel ===\n") + + // Basic goroutine + fmt.Println("=== Basic Goroutine ===") + go sayHello("Goroutine 1") + go sayHello("Goroutine 2") + go sayHello("Goroutine 3") + + // Sleep untuk memberi waktu goroutine selesai + time.Sleep(100 * time.Millisecond) + fmt.Println() + + // Anonymous goroutine + fmt.Println("=== Anonymous Goroutine ===") + go func() { + fmt.Println("Anonymous goroutine running") + }() + time.Sleep(50 * time.Millisecond) + fmt.Println() + + // Goroutine dengan parameter + fmt.Println("=== Goroutine dengan Parameter ===") + for i := 1; i <= 3; i++ { + go printNumber(i) + } + time.Sleep(100 * time.Millisecond) + fmt.Println() + + // Channel + fmt.Println("=== Basic Channel ===") + ch := make(chan string) + + go func() { + ch <- "Hello from channel" + }() + + message := <-ch + fmt.Println("Received:", message) + fmt.Println() + + // Channel dengan goroutine + fmt.Println("=== Channel Communication ===") + messages := make(chan string) + + go sendMessages(messages) + + msg1 := <-messages + msg2 := <-messages + fmt.Println("Received:", msg1) + fmt.Println("Received:", msg2) + fmt.Println() + + // Buffered channel + fmt.Println("=== Buffered Channel ===") + buffered := make(chan int, 3) + + buffered <- 1 + buffered <- 2 + buffered <- 3 + // Tidak perlu goroutine karena channel di-buffer + + fmt.Println("Received:", <-buffered) + fmt.Println("Received:", <-buffered) + fmt.Println("Received:", <-buffered) + fmt.Println() + + // Channel dengan range + fmt.Println("=== Channel dengan Range ===") + numbers := make(chan int) + + go func() { + for i := 1; i <= 5; i++ { + numbers <- i + } + close(numbers) // Penting: close channel setelah selesai + }() + + for num := range numbers { + fmt.Printf("Received number: %d\n", num) + } + fmt.Println() + + // Select statement + fmt.Println("=== Select Statement ===") + ch1 := make(chan string) + ch2 := make(chan string) + + go func() { + time.Sleep(50 * time.Millisecond) + ch1 <- "Message from channel 1" + }() + + go func() { + time.Sleep(100 * time.Millisecond) + ch2 <- "Message from channel 2" + }() + + for i := 0; i < 2; i++ { + select { + case msg1 := <-ch1: + fmt.Println("Received:", msg1) + case msg2 := <-ch2: + fmt.Println("Received:", msg2) + } + } + fmt.Println() + + // Select dengan default + fmt.Println("=== Select dengan Default ===") + ch3 := make(chan string) + + select { + case msg := <-ch3: + fmt.Println("Received:", msg) + default: + fmt.Println("No message received (non-blocking)") + } + fmt.Println() + + // WaitGroup + fmt.Println("=== WaitGroup ===") + var wg sync.WaitGroup + + for i := 1; i <= 3; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + fmt.Printf("Worker %d starting\n", id) + time.Sleep(50 * time.Millisecond) + fmt.Printf("Worker %d done\n", id) + }(i) + } + + wg.Wait() + fmt.Println("All workers completed") + fmt.Println() + + // Worker pool pattern + fmt.Println("=== Worker Pool ===") + jobs := make(chan int, 10) + results := make(chan int, 10) + + // Start 3 workers + for w := 1; w <= 3; w++ { + go worker(w, jobs, results) + } + + // Send 5 jobs + for j := 1; j <= 5; j++ { + jobs <- j + } + close(jobs) + + // Collect results + for a := 1; a <= 5; a++ { + result := <-results + fmt.Printf("Result: %d\n", result) + } + fmt.Println() + + // Mutex untuk sync + fmt.Println("=== Mutex ===") + demonstrateMutex() + fmt.Println() + + // Channel direction + fmt.Println("=== Channel Direction ===") + pings := make(chan string, 1) + pongs := make(chan string, 1) + + ping(pings, "Hello") + pong(pings, pongs) + fmt.Println(<-pongs) + fmt.Println() + + // Timeout pattern + fmt.Println("=== Timeout Pattern ===") + ch4 := make(chan string, 1) + + go func() { + time.Sleep(200 * time.Millisecond) + ch4 <- "Result" + }() + + select { + case res := <-ch4: + fmt.Println("Received:", res) + case <-time.After(100 * time.Millisecond): + fmt.Println("Timeout!") + } + fmt.Println() + + // Ticker + fmt.Println("=== Ticker ===") + ticker := time.NewTicker(50 * time.Millisecond) + done := make(chan bool) + + go func() { + count := 0 + for { + select { + case <-done: + return + case t := <-ticker.C: + count++ + fmt.Printf("Tick at %v (count: %d)\n", t.Format("15:04:05.000"), count) + } + } + }() + + time.Sleep(200 * time.Millisecond) + ticker.Stop() + done <- true + fmt.Println("Ticker stopped") +} + +func sayHello(name string) { + fmt.Printf("Hello from %s\n", name) +} + +func printNumber(num int) { + fmt.Printf("Number: %d\n", num) +} + +func sendMessages(ch chan string) { + ch <- "First message" + ch <- "Second message" +} + +func worker(id int, jobs <-chan int, results chan<- int) { + for j := range jobs { + fmt.Printf("Worker %d processing job %d\n", id, j) + time.Sleep(50 * time.Millisecond) + results <- j * 2 + } +} + +// Mutex example +type SafeCounter struct { + mu sync.Mutex + value int +} + +func (c *SafeCounter) Increment() { + c.mu.Lock() + c.value++ + c.mu.Unlock() +} + +func (c *SafeCounter) Value() int { + c.mu.Lock() + defer c.mu.Unlock() + return c.value +} + +func demonstrateMutex() { + counter := SafeCounter{value: 0} + var wg sync.WaitGroup + + for i := 0; i < 1000; i++ { + wg.Add(1) + go func() { + defer wg.Done() + counter.Increment() + }() + } + + wg.Wait() + fmt.Printf("Final counter value: %d\n", counter.Value()) +} + +// Channel dengan direction (send-only dan receive-only) +func ping(pings chan<- string, msg string) { + pings <- msg +} + +func pong(pings <-chan string, pongs chan<- string) { + msg := <-pings + pongs <- msg +} diff --git a/examples/11_errorhandling.go b/examples/11_errorhandling.go new file mode 100644 index 0000000..6facdb8 --- /dev/null +++ b/examples/11_errorhandling.go @@ -0,0 +1,331 @@ +package main + +import ( + "errors" + "fmt" + "os" +) + +func main() { + fmt.Println("=== Contoh Error Handling di Golang ===\n") + + // Basic error handling + fmt.Println("=== Basic Error ===") + result, err := divide(10, 2) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Printf("10 / 2 = %.2f\n", result) + } + + result, err = divide(10, 0) + if err != nil { + fmt.Println("Error:", err) + } + fmt.Println() + + // Errors.New + fmt.Println("=== Creating Errors ===") + err1 := errors.New("something went wrong") + fmt.Println("Error 1:", err1) + + // fmt.Errorf untuk error dengan format + value := 42 + err2 := fmt.Errorf("invalid value: %d", value) + fmt.Println("Error 2:", err2) + fmt.Println() + + // Custom error type + fmt.Println("=== Custom Error Type ===") + var err3 error = &ValidationError{ + Field: "email", + Message: "invalid email format", + } + fmt.Println("Error 3:", err3) + + // Type assertion untuk custom error + if ve, ok := err3.(*ValidationError); ok { + fmt.Printf("Validation failed on field '%s': %s\n", ve.Field, ve.Message) + } + fmt.Println() + + // Multiple return dengan error + fmt.Println("=== Multiple Return with Error ===") + user, err := getUser(1) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Printf("User: %+v\n", user) + } + + _, err = getUser(999) + if err != nil { + fmt.Println("Error:", err) + } + fmt.Println() + + // Error wrapping (Go 1.13+) + fmt.Println("=== Error Wrapping ===") + err4 := processData() + if err4 != nil { + fmt.Println("Error:", err4) + + // Check wrapped error + if errors.Is(err4, ErrNotFound) { + fmt.Println("This is a 'not found' error") + } + } + fmt.Println() + + // Defer for cleanup + fmt.Println("=== Defer for Cleanup ===") + err = writeToFile("/tmp/test.txt", "Hello, World!") + if err != nil { + fmt.Println("Error writing file:", err) + } else { + fmt.Println("File written successfully") + } + fmt.Println() + + // Panic and Recover + fmt.Println("=== Panic and Recover ===") + fmt.Println("Starting risky operation...") + safeDivide(10, 2) + safeDivide(10, 0) + fmt.Println("Program continues after panic recovery") + fmt.Println() + + // Multiple error checks + fmt.Println("=== Multiple Error Checks ===") + if err := step1(); err != nil { + fmt.Println("Step 1 failed:", err) + return + } + if err := step2(); err != nil { + fmt.Println("Step 2 failed:", err) + return + } + if err := step3(); err != nil { + fmt.Println("Step 3 failed:", err) + return + } + fmt.Println("All steps completed successfully") + fmt.Println() + + // Error handling in loop + fmt.Println("=== Error Handling in Loop ===") + processItems() + fmt.Println() + + // Sentinel errors + fmt.Println("=== Sentinel Errors ===") + err = performOperation() + if errors.Is(err, ErrNotFound) { + fmt.Println("Handling not found error") + } else if errors.Is(err, ErrUnauthorized) { + fmt.Println("Handling unauthorized error") + } else if err != nil { + fmt.Println("Unknown error:", err) + } + fmt.Println() + + // Custom error with additional context + fmt.Println("=== Error with Context ===") + opErr := &OperationError{ + Op: "database query", + Path: "/users/123", + Err: errors.New("connection timeout"), + } + fmt.Println("Operation error:", opErr) + fmt.Println() + + // Best practices + fmt.Println("=== Best Practices Demo ===") + demonstrateBestPractices() +} + +// Basic error function +func divide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("division by zero") + } + return a / b, nil +} + +// Custom error type +type ValidationError struct { + Field string + Message string +} + +func (e *ValidationError) Error() string { + return fmt.Sprintf("validation error on field '%s': %s", e.Field, e.Message) +} + +// User struct untuk example +type User struct { + ID int + Name string +} + +func getUser(id int) (*User, error) { + if id <= 0 { + return nil, errors.New("invalid user ID") + } + if id == 999 { + return nil, errors.New("user not found") + } + return &User{ID: id, Name: "John Doe"}, nil +} + +// Sentinel errors +var ( + ErrNotFound = errors.New("not found") + ErrUnauthorized = errors.New("unauthorized") + ErrInvalidInput = errors.New("invalid input") +) + +func processData() error { + // Simulasi error + return fmt.Errorf("failed to process: %w", ErrNotFound) +} + +func performOperation() error { + // Simulasi error + return ErrNotFound +} + +// File operations dengan defer +func writeToFile(filename, data string) error { + file, err := os.Create(filename) + if err != nil { + return fmt.Errorf("failed to create file: %w", err) + } + defer file.Close() // Always close file + + _, err = file.WriteString(data) + if err != nil { + return fmt.Errorf("failed to write to file: %w", err) + } + + return nil +} + +// Panic and recover +func safeDivide(a, b int) { + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from panic:", r) + } + }() + + result := a / b + fmt.Printf("%d / %d = %d\n", a, b, result) +} + +// Steps dengan error +func step1() error { + fmt.Println("Executing step 1...") + return nil +} + +func step2() error { + fmt.Println("Executing step 2...") + return nil +} + +func step3() error { + fmt.Println("Executing step 3...") + return nil +} + +// Error handling in loop +func processItems() { + items := []int{1, 2, 3, 4, 5} + + for i, item := range items { + if err := processItem(item); err != nil { + fmt.Printf("Error processing item %d: %v\n", i, err) + continue // Skip to next item + } + fmt.Printf("Processed item %d successfully\n", i) + } +} + +func processItem(item int) error { + if item == 3 { + return errors.New("item 3 cannot be processed") + } + return nil +} + +// Custom error with context +type OperationError struct { + Op string + Path string + Err error +} + +func (e *OperationError) Error() string { + return fmt.Sprintf("%s %s: %v", e.Op, e.Path, e.Err) +} + +func (e *OperationError) Unwrap() error { + return e.Err +} + +// Best practices demonstration +func demonstrateBestPractices() { + // 1. Always check errors + data, err := readData() + if err != nil { + fmt.Println("Error reading data:", err) + return + } + fmt.Println("Data read:", data) + + // 2. Provide context in errors + err = validateInput("") + if err != nil { + fmt.Println("Validation error:", err) + } + + // 3. Use defer for cleanup + cleanup() + + // 4. Don't panic in libraries, return errors + result, err := libraryFunction(10) + if err != nil { + fmt.Println("Library error:", err) + } else { + fmt.Println("Library result:", result) + } +} + +func readData() (string, error) { + // Simulasi membaca data + success := true + if !success { + return "", errors.New("failed to read data") + } + return "sample data", nil +} + +func validateInput(input string) error { + if input == "" { + return fmt.Errorf("validation failed: input cannot be empty") + } + return nil +} + +func cleanup() { + defer fmt.Println("Cleanup completed") + fmt.Println("Performing cleanup...") +} + +func libraryFunction(value int) (int, error) { + if value < 0 { + return 0, errors.New("value cannot be negative") + } + return value * 2, nil +}