Progress belajar
Modul 3 dari 73
0% 0/73 modul selesai
Setelah selesai, tandai modul ini agar progres kursus tetap rapi.
Progress disimpan lokal di browser ini.
Variabel, Tipe,
dan Zero Value
Di Go, data tidak sekadar disimpan. Data diberi kontrak tipe yang jelas sejak program dikompilasi, jauh sebelum baris pertama dijalankan.
Kenapa Sistem Tipe Go Terasa Berbeda
Dari fleksibilitas JavaScript menuju kontrak eksplisit Go
Kamu sudah mengenal TypeScript sebagai lapisan tipe di atas JavaScript, tetapi Go membawa tipe turun ke level bahasa dan compiler, bukan sekadar bantuan saat menulis kode.
Di JavaScript, sebuah nilai bisa berganti tipe saat program berjalan. Di TypeScript, tipe membantu saat development, tetapi hasil akhirnya tetap JavaScript yang dieksekusi runtime. Di Go, tipe adalah bagian dari bahasa yang diperiksa compiler sebelum program berjalan, sehingga banyak bug ketahuan lebih awal, terutama di backend yang berurusan dengan harga, stok, status produk, dan payload API.
Anggap Go seperti TypeScript tanpa mode longgar: tidak ada any sebagai jalan pintas harian, tidak ada coercion diam-diam, dan nilai kosong pun selalu punya bentuk yang jelas menurut tipenya.
Ada satu perbedaan halus yang penting untuk pembaca dari TypeScript. TypeScript memakai structural typing, jadi dua tipe dengan bentuk sama dianggap kompatibel. Go memakai named typing, jadi type ProductStatus string adalah tipe yang benar-benar baru dan tidak otomatis bisa dipertukarkan dengan string. Konsekuensi ini akan terasa jelas saat kita membahas custom type.
Sekumpulan aturan yang menentukan jenis nilai apa yang boleh disimpan, dikirim ke fungsi, dibandingkan, dikonversi, dan dikembalikan oleh program Go, diperiksa oleh compiler sebelum eksekusi.
Modul ini tidak mengajari variabel dari nol. Fokusnya adalah cara berpikir Go saat kamu memodelkan data backend online shop skincare, lewat var dan :=, const, tipe dasar, zero value, konversi tipe, custom type, dan type alias.
Dokumentasi resmi yang relevan: Go Specification, A Tour of Go: Basic types, A Tour of Go: Zero values, Constants (Go Blog), dan Go Modules Reference.
var dan Short Declaration
Dua cara deklarasi, dua konteks penggunaan
Go punya var untuk deklarasi yang bisa eksplisit dan := untuk deklarasi ringkas di dalam fungsi.
Di JavaScript kamu terbiasa memakai let dan const. Di Go, pilihan paling sering adalah var atau short declaration :=. Keduanya membuat variabel, tetapi aturan tempat pakainya berbeda, dan perbedaan itulah yang sering membuat pendatang baru tersandung.
let price = 129000membuat variabel runtime.const status = "active"mengunci binding, bukan selalu isi objek.- Tipe bisa diinfer TypeScript, tetapi runtime tetap JavaScript.
var price int = 129000boleh di level package atau di dalam fungsi.status := "active"hanya boleh di dalam fungsi.- Tipe diinfer compiler dan menjadi bagian dari program Go.
Tiga bentuk deklarasi yang perlu kamu kenal
Go memberi tiga cara menulis variabel: eksplisit dengan tipe, var dengan inferensi, dan short declaration. Ketiganya menghasilkan variabel, hanya beda gaya dan tempat.
cmd/playground/declare.gopackage main import "fmt" func main() { var price int = 129000 // var eksplisit dengan tipe var stock = 12 // var dengan inferensi tipe (int) name := "Niacinamide Serum" // short declaration, hanya di dalam fungsi fmt.Println(price, stock, name) }
Aturan praktis
Gunakan var saat kamu butuh deklarasi di level package, ingin menulis tipe secara jelas, atau sengaja memanfaatkan zero value. Gunakan := untuk nilai lokal di dalam fungsi saat tipenya sudah jelas dari sisi kanan.
flowchart TD
A["Mau mendeklarasikan variabel"] --> B{"Di dalam fungsi?"}
B -->|"Tidak, level package"| C["Pakai var, const, type, atau func"]
B -->|"Ya, di dalam fungsi"| D{"Tipe jelas dari sisi kanan?"}
D -->|"Ya, ingin ringkas"| E["Pakai short declaration :="]
D -->|"Butuh tipe eksplisit atau zero value"| F["Pakai var"]Gambar 1. var bisa dipakai di mana saja, sedangkan := hanya hidup di dalam fungsi. Saat ragu di level package, jawabannya selalu var, const, type, atau func.
cmd/playground/main.gopackage main import "fmt" var appName string = "skincare-backend" var maxFeaturedProducts int func main() { storeName := "GlowLab" isActive := true fmt.Println(appName) fmt.Println(storeName) fmt.Println(isActive) fmt.Println(maxFeaturedProducts) }
Perhatikan maxFeaturedProducts tidak diberi nilai awal, tetapi Go tetap memberinya nilai aman, yaitu 0 untuk int. Kita bahas lebih dalam di section zero value.
:= hanya boleh dipakai di dalam fungsi. Untuk level package, pakai var, const, type, atau deklarasi fungsi.
cmd/playground/invalid.gopackage main productName := "Hydrating Toner" // tidak valid di level package func main() {}
contoh error compilersyntax error: non-declaration statement outside function body
Short declaration harus memperkenalkan minimal satu nama baru
Di Go, := bukan operator update. Ia mendeklarasikan variabel baru. Bila semua nama di sisi kiri sudah ada dalam scope yang sama, compiler menolak. Namun bila ada minimal satu nama baru, := boleh dipakai walau sebagian nama lama ikut ditugasi ulang.
cmd/playground/redeclare.gopackage main import "fmt" func main() { quantity := 2 quantity = 3 // assignment biasa, bukan deklarasi productName, quantity := "Serum", 4 // valid: productName nama baru fmt.Println(productName, quantity) }
Baris productName, quantity := "Serum", 4 valid karena productName adalah nama baru, walaupun quantity sudah ada. Pola ini sering muncul saat fungsi mengembalikan dua nilai, misalnya result, err := doSomething(), lalu err dipakai ulang di pemanggilan berikutnya.
const dan Tipe Dasar
Konstanta Go bukan object freeze ala JavaScript
const di Go menyimpan nilai konstan untuk angka, string, rune, dan boolean, bukan object, slice, atau map.
Di JavaScript, const berarti binding tidak bisa diarahkan ke nilai lain, tetapi object atau array di dalamnya tetap bisa dimutasi. Di Go, const adalah nilai yang sudah pasti pada compile-time untuk jenis nilai tertentu, jadi kamu tidak membuat konstanta slice, map, struct, atau objek kompleks.
const JavaScript mengunci nama variabel, sedangkan const Go mendeklarasikan nilai konstan yang sudah diketahui compiler. Karena itu const Go cocok untuk status teks, batas angka, kode mata uang, atau flag tetap.
internal/product/constants.gopackage product const DefaultPageSize = 20 const MaxPageSize = 100 const CurrencyCode = "IDR" const IsCatalogPublic = true
Tipe dasar yang akan sering kamu pakai di awal proyek skincare adalah string, int, int64, float64, dan bool.
string
Untuk nama produk, slug, SKU, kategori, email, dan status berbasis teks.
int
Untuk hitungan di memori aplikasi, seperti quantity di cart atau jumlah hasil.
int64
Untuk ID database, harga dalam rupiah, dan nilai numerik yang butuh ukuran eksplisit.
float64
Untuk angka yang memang pecahan seperti rating rata-rata, bukan untuk uang.
bool
Untuk flag seperti aktif, terbit, tersedia, atau alamat default.
const
Untuk nilai tetap seperti default page size, kode mata uang, atau batas paginasi.
internal/product/basic_types.gopackage product type Product struct { ID int64 Name string PriceRupiah int64 Quantity int IsActive bool }
Sepanjang proyek ini, harga disimpan sebagai PriceRupiah int64, bukan float64. Floating point menyimpan 0.1 + 0.2 tidak persis, dan untuk uang itu bisa membuat total checkout meleset satu rupiah. Float kita simpan hanya untuk nilai yang memang pecahan seperti rating.
Konstanta typed dan untyped
Ini bagian yang sering membingungkan, padahal sangat berguna. Konstanta tanpa tipe eksplisit, seperti const DefaultPageSize = 20, disebut untyped constant. Ia punya default type (di sini int), tetapi bisa menyesuaikan diri ke konteks numeric lain tanpa konversi manual selama nilainya muat.
Konstanta yang dideklarasikan tanpa tipe, misalnya const x = 20. Ia punya default type (int, float64, string, bool, atau rune) tetapi bisa otomatis menyesuaikan diri saat dipakai di konteks tipe lain yang kompatibel.
cmd/playground/const_kind.gopackage main import "fmt" const DefaultPageSize = 20 // untyped int constant const MaxPageSize int = 100 // typed: selalu int func main() { var limit int = DefaultPageSize // ok var ratio float64 = DefaultPageSize // ok juga, untyped menyesuaikan ke float64 // var bad float64 = MaxPageSize // ERROR: butuh float64(MaxPageSize) var ok float64 = float64(MaxPageSize) fmt.Println(limit, ratio, ok) }
Karena DefaultPageSize untyped, ia bisa langsung dipakai sebagai int maupun float64. Sebaliknya MaxPageSize sudah typed int, jadi memakainya sebagai float64 butuh konversi eksplisit. Aturan sederhananya: biarkan konstanta untyped kecuali kamu memang ingin mengunci tipenya.
Untuk angka dan teks tetap seperti DefaultPageSize atau CurrencyCode, tulis tanpa tipe agar fleksibel. Tambahkan tipe hanya saat kamu sengaja ingin membatasi, misalnya const MaxRetry uint8 = 3.
Zero Value, Nilai Awal yang Aman
Konsep penting yang tidak punya padanan langsung di JavaScript
Di Go, variabel yang dideklarasikan tanpa nilai selalu mendapat nilai awal sesuai tipenya, jadi tidak pernah ada keadaan undefined.
Di JavaScript, variabel yang belum diisi bernilai undefined. Di Go tidak ada undefined. Numeric menjadi 0, string menjadi string kosong, bool menjadi false, sedangkan pointer, slice, dan map menjadi nil.
Di JS, variabel tanpa isi sering berarti undefined, sumber klasik bug cannot read property of undefined. Di Go, variabel tanpa isi tetap punya nilai valid menurut tipenya, jadi banyak kelas bug itu hilang sejak awal.
Nilai default otomatis yang diberikan Go ketika variabel dideklarasikan tanpa initializer: 0 untuk numeric, "" untuk string, false untuk bool, dan nil untuk pointer, slice, dan map.
cmd/playground/zero_value.gopackage main import "fmt" func main() { var quantity int var productName string var price float64 var isActive bool var note *string fmt.Printf("quantity: %d\n", quantity) fmt.Printf("productName: %q\n", productName) fmt.Printf("price: %.2f\n", price) fmt.Printf("isActive: %t\n", isActive) fmt.Printf("note is nil: %t\n", note == nil) }
outputquantity: 0 productName: "" price: 0.00 isActive: false note is nil: true
flowchart LR
A["Deklarasi tanpa nilai awal"] --> B{"Tipe variabel"}
B -->|"int, int64, float64"| C["0"]
B -->|"string"| D["string kosong"]
B -->|"bool"| E["false"]
B -->|"pointer, slice, map"| F["nil"]
C --> G["Variabel langsung valid, bukan undefined"]
D --> G
E --> G
F --> GGambar 2. Zero value membuat setiap variabel Go punya nilai awal yang valid menurut tipenya, sehingga tidak ada keadaan undefined seperti di JavaScript.
Zero value juga berlaku untuk struct. Sebuah Product{} kosong langsung bisa dipakai, dan setiap field-nya terisi zero value masing-masing.
cmd/playground/zero_struct.gopackage main import "fmt" type Product struct { ID int64 Name string PriceRupiah int64 IsActive bool } func main() { var p Product // semua field zero value fmt.Printf("%+v\n", p) // {ID:0 Name: PriceRupiah:0 IsActive:false} }
Quantity bernilai 0 valid sebagai angka, tetapi mungkin tidak sah untuk checkout. Status berupa string kosong valid sebagai tipe, tetapi tidak masuk akal sebagai status produk. Karena itu validasi domain tetap diperlukan.
internal/cart/validation.gopackage cart import "errors" var ErrInvalidQuantity = errors.New("quantity must be greater than zero") func ValidateQuantity(quantity int) error { if quantity <= 0 { return ErrInvalidQuantity } return nil }
Zero value sering dimanfaatkan agar struct bisa langsung dipakai setelah deklarasi tanpa constructor. Tetapi aturan bisnis tetap harus memvalidasi apakah nilai itu masuk akal sebelum disimpan atau diproses.
Konversi Tipe Eksplisit
Tidak ada implicit coercion seperti JavaScript
Go tidak mengubah tipe numeric secara diam-diam. Setiap perpindahan tipe harus kamu tulis eksplisit, agar pembaca dan compiler sama-sama sadar.
JavaScript sangat permisif. Ekspresi "10" + 2 menghasilkan string, sementara "10" - 2 menghasilkan angka. Di backend, perilaku seperti ini berbahaya karena nilai dari request, database, dan kalkulasi bisnis bisa tercampur tanpa sadar. Go memilih pendekatan eksplisit: int, int64, dan float64 adalah tipe berbeda, dan kamu harus mengubahnya secara sadar.
flowchart LR A["Nilai bertipe int"] -->|"butuh float64(x)"| B["Nilai bertipe float64"] B -->|"butuh int64(y)"| A C["int * float64 tanpa konversi"] --> D["compile error: mismatched types"]
Gambar 3. int dan float64 adalah dua pulau tipe terpisah. Satu-satunya jembatan adalah konversi eksplisit; operasi langsung antar pulau ditolak compiler.
Contoh nyata di toko skincare adalah menghitung rating rata-rata. Total bintang dan jumlah review keduanya int, tetapi hasilnya harus pecahan, jadi kita konversi dulu.
cmd/playground/rating.gopackage main import "fmt" func main() { totalStars := 22 reviewCount := 5 naive := totalStars / reviewCount // 4, pembagian int membuang sisa avg := float64(totalStars) / float64(reviewCount) // 4.4 fmt.Println(naive) fmt.Printf("%.1f\n", avg) }
Kode berikut tidak valid karena reviewCount bertipe int, sedangkan avgRating bertipe float64.
cmd/playground/invalid_conversion.gopackage main func main() { reviewCount := 5 avgRating := 4.4 _ = reviewCount * avgRating // tidak valid }
contoh error compilerinvalid operation: reviewCount * avgRating (mismatched types int and float64)
JavaScript sering melakukan coercion implisit yang sulit dilacak. Go memaksa kamu menulis float64(reviewCount) agar perubahan tipe terlihat jelas di kode, bukan terjadi diam-diam.
Harga tetap int64, konversi hanya untuk hitung persen
Karena uang disimpan int64, perhitungan diskon persen harus mampir sebentar ke float64, lalu kembali ke int64. Di sinilah konversi eksplisit benar-benar terpakai di domain.
internal/pricing/discount.gopackage pricing import "math" // ApplyPercentDiscount memotong harga (rupiah) sebesar persen tertentu. // Uang tetap int64; float64 hanya dipakai sesaat untuk hitung persen, lalu dibulatkan. func ApplyPercentDiscount(priceRupiah int64, percent float64) int64 { discounted := float64(priceRupiah) * (1 - percent/100) return int64(math.Round(discounted)) }
int64(2.9) menghasilkan 2, bukan 3. Konversi numeric ke integer di Go selalu membuang bagian desimal. Bila kamu memang ingin membulatkan harga diskon, pakai math.Round sebelum konversi seperti contoh di atas.
Konversi numeric ke string butuh package khusus
Untuk mengubah angka menjadi teks tampilan, pakai package strconv atau fmt. Jangan memakai string(65) untuk membuat teks angka, karena itu mengubah kode karakter menjadi rune.
cmd/playground/strconv.gopackage main import ( "fmt" "strconv" ) func main() { productID := int64(42) quantity := 3 idText := strconv.FormatInt(productID, 10) qtyText := strconv.Itoa(quantity) bad := string(65) // "A", bukan "65": go vet akan memperingatkan ini fmt.Println(idText, qtyText, bad) }
Di JS kamu memakai String(x) dan Number(x) atau parseInt. Di Go, arah angka ke teks memakai strconv.Itoa atau strconv.FormatInt, sedangkan teks ke angka memakai strconv.Atoi atau strconv.ParseInt, yang sama-sama mengembalikan error bila format gagal. Pola ini akan sering kamu pakai saat membaca query param di modul API.
Custom Type dan Type Alias
Membedakan domain type dari sekadar tipe bawaan
Go memungkinkan kamu membuat tipe baru agar aturan domain lebih ekspresif dan lebih sulit tertukar.
Custom type dibuat dengan bentuk type Nama TipeDasar. Hasilnya tipe baru yang berbeda dari tipe dasarnya, walaupun representasi nilainya sama. Alias dibuat dengan bentuk type Nama = TipeDasar, dengan tanda sama dengan, dan ia hanya nama lain untuk tipe yang persis sama.
flowchart TB
subgraph c["type ProductStatus string (custom type)"]
A["ProductStatus"] -->|"tipe BARU, beda dari string"| B["butuh konversi: ProductStatus(s) atau string(ps)"]
end
subgraph al["type UserID = int64 (alias)"]
C["UserID"] -->|"nama lain, tipe SAMA"| D["bebas dipertukarkan dengan int64"]
endGambar 4. Tanpa tanda sama dengan, type membuat tipe baru yang butuh konversi. Dengan tanda sama dengan, type hanya memberi nama lain untuk tipe yang sama.
internal/product/status.gopackage product type ProductStatus string const ( ProductStatusDraft ProductStatus = "draft" ProductStatusActive ProductStatus = "active" ProductStatusArchived ProductStatus = "archived" ProductStatusOutOfStock ProductStatus = "out_of_stock" ) func (s ProductStatus) IsSellable() bool { return s == ProductStatusActive }
Custom type seperti ProductStatus membuat kode domain lebih jelas. Fungsi yang menerima ProductStatus tidak bisa sembarangan diberi string lain tanpa konversi eksplisit, sehingga status acak tidak gampang menyelinap masuk.
internal/product/check.gopackage product func CanShowInCatalog(status ProductStatus, isActive bool) bool { return isActive && status.IsSellable() }
Di TypeScript, type UserId = number hanya alias struktural, jadi number apa pun bisa masuk. Di Go, type UserID int64 tanpa tanda sama dengan membuat tipe nominal yang benar-benar baru, mirip branded type yang harus kamu ciptakan manual di TS. Inilah cara Go mencegah ID pengguna tertukar dengan ID produk.
Enum rapi dengan iota
Saat status tidak perlu disimpan sebagai teks, iota memberi cara ringkas membuat enum integer berurutan. Cocok untuk konsep berjenjang seperti tier membership pelanggan.
internal/customer/tier.gopackage customer type MembershipTier int const ( TierBronze MembershipTier = iota // 0 TierSilver // 1 TierGold // 2 TierPlatinum // 3 ) func (t MembershipTier) FreeShipping() bool { return t >= TierGold }
Nilai iota bergantung pada urutan baris, jadi menyisipkan tier baru di tengah dapat menggeser angka lama dan merusak data yang sudah tersimpan. Untuk enum yang ditulis ke database atau JSON, lebih aman memakai string seperti ProductStatus atau menetapkan angka eksplisit.
Type alias dan kapan memakainya
Alias tidak membuat tipe baru. Ia berguna saat kamu ingin memberi nama domain tanpa mengubah kompatibilitas tipe dasar, atau saat memindahkan tipe antar package secara bertahap tanpa memecah kode lama sekaligus.
internal/identity/types.gopackage identity type UserID = int64
Pilih custom type untuk konsep domain yang punya aturan sendiri, seperti ProductStatus, OrderStatus, atau MembershipTier. Pilih alias hanya untuk transisi, kompatibilitas, atau memperjelas pembacaan. Di kode aplikasi, custom type jauh lebih sering tepat daripada alias.
Setelah menulis const block atau struct, jalankan gofmt. Formatter Go merapikan alignment dan spacing secara otomatis, jadi tidak perlu berdebat soal gaya manual di code review.
Model Domain Online Shop Skincare
Dari tipe dasar menuju model produk yang nyata
Sekarang kita rangkai semua yang dipelajari menjadi model produk skincare yang sederhana tetapi aman.
Untuk online shop skincare, data produk minimal punya ID, nama, harga, stok, status, dan flag aktif. Kita mulai dari model ringan. Nanti, saat masuk roadmap domain dan database, model ini dipisah lebih rapi sesuai layer.
- cmd/
- playground/
- main.go menjalankan contoh kecil
- internal/
- product/
- product.go model produk sederhana
- status.go custom type status produk
internal/product/status.gopackage product type ProductStatus string const ( ProductStatusDraft ProductStatus = "draft" ProductStatusActive ProductStatus = "active" ProductStatusArchived ProductStatus = "archived" ProductStatusOutOfStock ProductStatus = "out_of_stock" ) func (s ProductStatus) IsSellable() bool { return s == ProductStatusActive }
internal/product/product.gopackage product type Product struct { ID int64 Name string PriceRupiah int64 Quantity int Status ProductStatus IsActive bool } func (p Product) IsAvailable() bool { return p.IsActive && p.Quantity > 0 && p.Status.IsSellable() }
classDiagram
class Product {
+int64 ID
+string Name
+int64 PriceRupiah
+int Quantity
+ProductStatus Status
+bool IsActive
+IsAvailable() bool
}
class ProductStatus {
<<string>>
+IsSellable() bool
}
Product --> ProductStatus : StatusGambar 5. Semua konsep modul ini berkumpul: tipe dasar untuk field, custom type ProductStatus dengan method-nya sendiri, dan int64 untuk harga agar uang tetap presisi.
cmd/playground/main.gopackage main import ( "fmt" "github.com/kamu/skincare-backend/internal/product" ) func main() { serum := product.Product{ ID: 1001, Name: "Niacinamide Serum", PriceRupiah: 129000, Quantity: 12, Status: product.ProductStatusActive, IsActive: true, } fmt.Println(serum.Name) fmt.Println(serum.IsAvailable()) }
Model ini sengaja sederhana agar fokus ke tipe. Di modul berikutnya kita mulai bicara control flow, function, dan validasi yang lebih kaya, lalu memisahkan domain model dari DTO JSON saat masuk struct dan API.
Hands-on Ringan
Latihan kecil untuk menempelkan kebiasaan tipe eksplisit
Latihan ini membuat kamu merasakan langsung bedanya deklarasi, zero value, konversi, dan custom type dalam satu project kecil.
Pakai project github.com/kamu/skincare-backend, lalu tambahkan folder cmd/playground dan internal/product.
Buat ProductStatus agar status produk tidak lagi sekadar string bebas.
Pakai go run ./cmd/playground untuk melihat output struct produk sederhana.
Ganti Quantity menjadi 0, lalu lihat bagaimana IsAvailable berubah karena aturan domain, bukan karena tipe.
Terminalmkdir -p cmd/playground internal/product go run ./cmd/playground
Tambahkan fungsi kecil untuk menghitung subtotal. Karena harga int64, konversi yang terpaksa kita lakukan adalah pada quantity, bukan pada uangnya.
internal/product/pricing.gopackage product func CalculateSubtotal(priceRupiah int64, quantity int) int64 { return priceRupiah * int64(quantity) }
Lalu panggil dari main.go.
cmd/playground/main.gopackage main import ( "fmt" "github.com/kamu/skincare-backend/internal/product" ) func main() { serum := product.Product{ ID: 1001, Name: "Niacinamide Serum", PriceRupiah: 129000, Quantity: 2, Status: product.ProductStatusActive, IsActive: true, } subtotal := product.CalculateSubtotal(serum.PriceRupiah, serum.Quantity) fmt.Println(serum.Name) fmt.Println(serum.IsAvailable()) fmt.Println(subtotal) // 258000 }
Saat compiler menolak kode, baca pesannya pelan-pelan. Di Go, error compiler sering menjadi guru terbaik untuk memahami tipe, terutama pesan mismatched types yang menunjukkan persis di mana konversi kurang.
Jebakan Umum dari JS dan PHP
Kesalahan kecil yang sering muncul saat pindah ke Go
Sebagian besar bug awal di Go muncul karena membawa kebiasaan bahasa dinamis ke bahasa yang lebih eksplisit.
Mengira := bisa di mana saja
:= hanya berlaku di dalam fungsi. Untuk package-level, pakai var, const, type, atau func.
Mengira string kosong sama dengan belum ada
"" adalah nilai valid. Bila perlu membedakan belum diisi, pakai desain yang jelas seperti pointer atau tipe nullable saat masuk database.
Mengandalkan coercion
Go tidak akan mengalikan int dengan float64 tanpa konversi. Ini disengaja agar perubahan tipe terlihat.
Lupa pembagian int membuang sisa
22 / 5 menghasilkan 4, bukan 4.4. Konversi ke float64 dulu bila kamu memang butuh hasil pecahan.
Memakai float untuk uang
Floating point tidak presisi. Simpan harga sebagai int64 rupiah dan konversi hanya sesaat untuk hitung persen.
Status sebagai string bebas
Custom type seperti ProductStatus membuat domain lebih aman daripada menyebar string literal di banyak tempat.
:= bisa membuat variabel baru di scope dalam dengan nama yang sama. Ini valid, tetapi kadang membuat kamu mengubah variabel yang salah tanpa sadar.
cmd/playground/shadowing.gopackage main import "fmt" func main() { status := "active" if true { status := "draft" // variabel BARU, hanya hidup di dalam blok ini fmt.Println(status) } fmt.Println(status) // status luar tidak berubah }
outputdraft active
Contoh di atas benar secara sintaks, tetapi bisa menyesatkan. Di service layer nanti, shadowing seperti ini bisa membuat hasil validasi atau assignment terlihat benar padahal nilai di luar blok tidak pernah berubah.
Ringkasan & Poin Penting
Variabel dan tipe adalah fondasi kecil yang menentukan seberapa aman model domain kita saat proyek membesar.
Yang Wajib Menempel
varbisa dipakai di level package dan fungsi, sedangkan:=hanya untuk deklarasi lokal di dalam fungsi.constGo adalah nilai compile-time untuk string, boolean, rune, dan numeric, bukan object atau array seperti pola JavaScript.- Konstanta untyped menyesuaikan diri ke konteks tipe, sedangkan konstanta typed mengunci tipenya dan butuh konversi.
- Zero value membuat variabel Go selalu punya nilai awal: numeric
0, string kosong, boolfalse, dan pointer, slice, mapnil. - Go tidak melakukan coercion implisit antar tipe numeric. Konversi seperti
float64(quantity)harus ditulis eksplisit, dan konversi float ke int memotong desimal. - Custom type seperti
ProductStatusdanMembershipTiermembuat domain lebih aman, sedangkan alias sepertiUserID = int64hanya memberi nama lain untuk tipe yang sama. - Uang disimpan sebagai
int64rupiah, bukanfloat64, agar total tetap presisi.
Pemetaan ke proyek online shop skincare
Model domain
Product, ProductStatus, Quantity, PriceRupiah, dan IsActive menjadi fondasi entitas katalog yang akan tumbuh menjadi cart, order, dan inventory.
Lapisan berikutnya
Tipe yang aman ini menjadi bahan untuk validasi stok, aturan diskon, handler API, query PostgreSQL, dan DTO JSON di modul lanjutan.
Setelah data punya tipe yang jelas, modul berikutnya membahas control flow: if, switch, for, dan range, lalu gaya early return dan guard clause, agar kita bisa mulai menulis aturan bisnis seperti validasi stok dan aturan diskon.
Pastikan kamu bisa menjelaskan beda var dan :=, menyebut zero value tiap tipe dasar, menulis konversi float64(x) dan int64(y) dengan benar, serta membuat satu custom type berikut method-nya.
Progress disimpan lokal di browser ini.