Data type adalah konsep fundamental dalam programming yang menentukan jenis data yang dapat disimpan dan dimanipulasi dalam program. Go memiliki sistem type yang kuat dan static, yang berarti setiap variable harus memiliki type yang sudah ditentukan saat compile time.
Kategori Data Types di Go
Go memiliki beberapa kategori data type:
- Basic Types: int, float, bool, string
- Composite Types: array, slice, map, struct, channel
- Reference Types: pointer, interface, function
- Special Types: interface{}, nil
Mari kita bahas satu per satu.
Basic Types
Integer Types
Go menyediakan berbagai ukuran integer untuk kebutuhan yang berbeda:
package main
import "fmt"
func main() {
// Signed integers
var a int8 = 127 // -128 to 127
var b int16 = 32767 // -32,768 to 32,767
var c int32 = 2147483647 // -2,147,483,648 to 2,147,483,647
var d int64 = 9223372036854775807 // sangat besar
// Unsigned integers
var e uint8 = 255 // 0 to 255
var f uint16 = 65535 // 0 to 65,535
var g uint32 = 4294967295 // 0 to 4,294,967,295
var h uint64 = 18446744073709551615 // sangat besar
// Platform dependent
var i int = 42 // int32 atau int64 tergantung platform
var j uint = 42 // uint32 atau uint64 tergantung platform
var k uintptr = 12345 // untuk menyimpan pointer address
fmt.Println(a, b, c, d, e, f, g, h, i, j, k)
}
Floating Point Types
package main
import "fmt"
func main() {
var f32 float32 = 3.14159 // 32-bit floating point
var f64 float64 = 3.141592653589793 // 64-bit floating point
// Default adalah float64
var pi = 3.14159 // float64
fmt.Printf("float32: %.5f\n", f32)
fmt.Printf("float64: %.15f\n", f64)
fmt.Printf("default: %.5f\n", pi)
}
Boolean Type
package main
import "fmt"
func main() {
var isTrue bool = true
var isFalse bool = false
var defaultBool bool // false (zero value)
fmt.Println("isTrue:", isTrue)
fmt.Println("isFalse:", isFalse)
fmt.Println("defaultBool:", defaultBool)
// Boolean operations
result := isTrue && !isFalse
fmt.Println("result:", result) // true
}
String Type
package main
import "fmt"
func main() {
var nama string = "Budi Santoso"
var alamat = "Jakarta"
kota := "Bandung"
// String concatenation
fullAddress := alamat + ", " + kota
// String length
panjang := len(nama)
// Access character (returns byte)
firstChar := nama[0]
fmt.Println("Nama:", nama)
fmt.Println("Alamat lengkap:", fullAddress)
fmt.Println("Panjang nama:", panjang)
fmt.Println("Karakter pertama:", firstChar)
// Multiline string
pesan := `Ini adalah string
yang bisa lebih dari
satu baris tanpa escape character`
fmt.Println(pesan)
}
Composite Types
Array
Array adalah koleksi elemen dengan ukuran tetap dan type yang sama:
package main
import "fmt"
func main() {
// Deklarasi array
var numbers [5]int // [0 0 0 0 0]
var names [3]string = [3]string{"Ali", "Budi", "Citra"}
colors := [4]string{"merah", "hijau", "biru", "kuning"}
// Array dengan ukuran otomatis
fruits := [...]string{"apel", "jeruk", "mangga"}
// Mengakses elemen array
numbers[0] = 10
numbers[1] = 20
fmt.Println("Numbers:", numbers)
fmt.Println("Names:", names)
fmt.Println("Colors:", colors)
fmt.Println("Fruits:", fruits)
fmt.Println("Panjang fruits:", len(fruits))
// Iterasi array
for i, value := range colors {
fmt.Printf("Index %d: %s\n", i, value)
}
}
Slice
Slice adalah versi dinamis dari array:
package main
import "fmt"
func main() {
// Membuat slice
var numbers []int // slice kosong
names := []string{"Ali", "Budi"} // slice dengan data
colors := make([]string, 3) // slice dengan length 3
// Menambah elemen ke slice
numbers = append(numbers, 1, 2, 3)
names = append(names, "Citra")
// Slice dari array
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2 3 4]
slice2 := arr[:3] // [1 2 3]
slice3 := arr[2:] // [3 4 5]
fmt.Println("Numbers:", numbers)
fmt.Println("Names:", names)
fmt.Println("Colors:", colors)
fmt.Println("Slice1:", slice1)
fmt.Println("Slice2:", slice2)
fmt.Println("Slice3:", slice3)
// Length dan capacity
fmt.Printf("Slice1 - len: %d, cap: %d\n", len(slice1), cap(slice1))
}
Map
Map adalah struktur data key-value:
package main
import "fmt"
func main() {
// Membuat map
var ages map[string]int = make(map[string]int)
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Charlie": 92,
}
// Menambah/mengubah data
ages["Ali"] = 25
ages["Budi"] = 30
scores["Diana"] = 88
// Mengakses data
aliAge := ages["Ali"]
bobScore, exists := scores["Bob"] // cek apakah key ada
fmt.Println("Ages:", ages)
fmt.Println("Scores:", scores)
fmt.Println("Ali's age:", aliAge)
fmt.Println("Bob's score:", bobScore, "exists:", exists)
// Menghapus data
delete(scores, "Charlie")
fmt.Println("Scores after delete:", scores)
// Iterasi map
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
}
Struct
Struct adalah type yang mengelompokkan data dengan nama field:
package main
import "fmt"
// Definisi struct
type Person struct {
Name string
Age int
Email string
Address Address // nested struct
}
type Address struct {
Street string
City string
Country string
}
func main() {
// Membuat instance struct
var person1 Person
person1.Name = "Ali"
person1.Age = 25
person1.Email = "ali@email.com"
// Struct literal
person2 := Person{
Name: "Budi",
Age: 30,
Email: "budi@email.com",
Address: Address{
Street: "Jl. Merdeka 123",
City: "Jakarta",
Country: "Indonesia",
},
}
// Positional initialization
person3 := Person{"Citra", 28, "citra@email.com", Address{}}
fmt.Println("Person1:", person1)
fmt.Println("Person2:", person2)
fmt.Println("Person3:", person3)
// Mengakses field
fmt.Printf("%s berumur %d tahun\n", person2.Name, person2.Age)
fmt.Printf("Alamat: %s, %s\n", person2.Address.Street, person2.Address.City)
}
Pointer Types
Pointer menyimpan alamat memori dari variable lain:
package main
import "fmt"
func main() {
var x int = 42
var p *int = &x // p adalah pointer ke x
fmt.Println("Nilai x:", x)
fmt.Println("Alamat x:", &x)
fmt.Println("Nilai p:", p)
fmt.Println("Nilai yang ditunjuk p:", *p)
// Mengubah nilai melalui pointer
*p = 100
fmt.Println("x setelah diubah melalui pointer:", x)
// Pointer ke struct
type Point struct {
X, Y int
}
point := Point{10, 20}
pointPtr := &point
fmt.Printf("Point: %v\n", point)
fmt.Printf("Melalui pointer: X=%d, Y=%d\n", pointPtr.X, pointPtr.Y)
// Mengubah melalui pointer
pointPtr.X = 30
fmt.Printf("Point setelah diubah: %v\n", point)
}
Interface Types
Interface mendefinisikan kontrak method tanpa implementasi:
package main
import "fmt"
// Definisi interface
type Shape interface {
Area() float64
Perimeter() float64
}
// Struct yang mengimplementasi interface
type Rectangle struct {
Width, Height float64
}
type Circle struct {
Radius float64
}
// Method untuk Rectangle
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// Method untuk Circle
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
func main() {
var s Shape
// Rectangle implements Shape
s = Rectangle{Width: 10, Height: 5}
fmt.Printf("Rectangle - Area: %.2f, Perimeter: %.2f\n",
s.Area(), s.Perimeter())
// Circle implements Shape
s = Circle{Radius: 7}
fmt.Printf("Circle - Area: %.2f, Perimeter: %.2f\n",
s.Area(), s.Perimeter())
// Slice of interfaces
shapes := []Shape{
Rectangle{Width: 3, Height: 4},
Circle{Radius: 5},
Rectangle{Width: 2, Height: 8},
}
for i, shape := range shapes {
fmt.Printf("Shape %d - Area: %.2f\n", i+1, shape.Area())
}
}
Empty Interface
Interface kosong interface{}
dapat menyimpan nilai apa saja:
package main
import "fmt"
func main() {
var anything interface{}
anything = 42
fmt.Printf("Integer: %v, Type: %T\n", anything, anything)
anything = "Hello World"
fmt.Printf("String: %v, Type: %T\n", anything, anything)
anything = []int{1, 2, 3}
fmt.Printf("Slice: %v, Type: %T\n", anything, anything)
// Type assertion
str, ok := anything.([]int)
if ok {
fmt.Println("Type assertion berhasil:", str)
}
// Type switch
switch v := anything.(type) {
case int:
fmt.Println("Ini adalah integer:", v)
case string:
fmt.Println("Ini adalah string:", v)
case []int:
fmt.Println("Ini adalah slice of int:", v)
default:
fmt.Println("Type tidak diketahui")
}
}
Channel Types
Channel digunakan untuk komunikasi antar goroutine:
package main
import (
"fmt"
"time"
)
func main() {
// Membuat channel
ch := make(chan string)
numbers := make(chan int, 3) // buffered channel
// Mengirim data ke channel (dalam goroutine)
go func() {
ch <- "Hello dari goroutine"
}()
// Menerima data dari channel
message := <-ch
fmt.Println("Pesan:", message)
// Buffered channel
numbers <- 1
numbers <- 2
numbers <- 3
fmt.Println("Number 1:", <-numbers)
fmt.Println("Number 2:", <-numbers)
fmt.Println("Number 3:", <-numbers)
// Channel dengan select
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "dari ch1"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "dari ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println("Menerima:", msg1)
case msg2 := <-ch2:
fmt.Println("Menerima:", msg2)
}
}
}
Function Types
Function juga merupakan type di Go:
package main
import "fmt"
// Function type
type Operation func(int, int) int
func add(a, b int) int {
return a + b
}
func multiply(a, b int) int {
return a * b
}
func calculate(op Operation, x, y int) int {
return op(x, y)
}
func main() {
// Function sebagai variable
var operation Operation = add
result1 := operation(5, 3)
// Function sebagai parameter
result2 := calculate(multiply, 4, 6)
// Anonymous function
subtract := func(a, b int) int {
return a - b
}
result3 := calculate(subtract, 10, 4)
fmt.Println("Addition result:", result1) // 8
fmt.Println("Multiplication result:", result2) // 24
fmt.Println("Subtraction result:", result3) // 6
// Function sebagai return value
getOperation := func(name string) Operation {
switch name {
case "add":
return add
case "multiply":
return multiply
default:
return subtract
}
}
op := getOperation("add")
result4 := op(7, 2)
fmt.Println("Dynamic operation result:", result4) // 9
}
Type Conversion
Go memerlukan explicit conversion antar type:
package main
import "fmt"
func main() {
var i int = 42
var f float64 = float64(i) // int ke float64
var u uint = uint(f) // float64 ke uint
fmt.Printf("int: %d, float64: %.2f, uint: %d\n", i, f, u)
// String conversion
var s string = fmt.Sprintf("%d", i) // int ke string
fmt.Printf("string: %s\n", s)
// Byte slice ke string dan sebaliknya
text := "Hello World"
bytes := []byte(text) // string ke []byte
backToString := string(bytes) // []byte ke string
fmt.Printf("Original: %s\n", text)
fmt.Printf("Bytes: %v\n", bytes)
fmt.Printf("Back to string: %s\n", backToString)
// Type assertion untuk interface
var anything interface{} = "Hello"
str, ok := anything.(string)
if ok {
fmt.Printf("Type assertion berhasil: %s\n", str)
}
}
Zero Values
Setiap type memiliki zero value default:
package main
import "fmt"
func main() {
// Basic types zero values
var i int
var f float64
var b bool
var s string
// Composite types zero values
var arr [3]int
var slice []int
var m map[string]int
var p *int
var ch chan int
// Struct zero value
type Person struct {
Name string
Age int
}
var person Person
fmt.Printf("int: %d\n", i) // 0
fmt.Printf("float64: %.1f\n", f) // 0.0
fmt.Printf("bool: %t\n", b) // false
fmt.Printf("string: '%s'\n", s) // ""
fmt.Printf("array: %v\n", arr) // [0 0 0]
fmt.Printf("slice: %v\n", slice) // []
fmt.Printf("map: %v\n", m) // map[]
fmt.Printf("pointer: %v\n", p) // <nil>
fmt.Printf("channel: %v\n", ch) // <nil>
fmt.Printf("struct: %v\n", person) // { 0}
// Cek nil
fmt.Printf("slice == nil: %t\n", slice == nil)
fmt.Printf("map == nil: %t\n", m == nil)
fmt.Printf("pointer == nil: %t\n", p == nil)
fmt.Printf("channel == nil: %t\n", ch == nil)
}
Best Practices
1. Pilih Type yang Tepat
// Gunakan int untuk counter/index umum
for i := 0; i < 10; i++ {
// ...
}
// Gunakan uint8 untuk byte data
var pixels []uint8
// Gunakan float64 untuk scientific calculation
var pi float64 = 3.141592653589793
// Gunakan bool untuk flag
var isActive bool = true
2. Gunakan Slice daripada Array untuk Fleksibilitas
// Lebih fleksibel
func processItems(items []string) {
// ...
}
// Kurang fleksibel
func processItems(items [10]string) {
// ...
}
3. Inisialisasi Map dan Slice
// BAIK: inisialisasi eksplisit
m := make(map[string]int)
s := make([]int, 0)
// BURUK: menggunakan nil map/slice langsung
var m map[string]int
// m["key"] = 1 // panic: assignment to entry in nil map
4. Gunakan Struct untuk Data yang Terkait
// BAIK: grouped data
type User struct {
ID int
Name string
Email string
}
// BURUK: separate variables
var userID int
var userName string
var userEmail string
Latihan
Latihan 1: Basic Types
package main
import "fmt"
func main() {
// TODO: Deklarasikan variable dengan berbagai basic type:
// - umur (int): 25
// - tinggi (float64): 175.5
// - nama (string): "Andi"
// - lulus (bool): true
// Tampilkan semua variable dan typenya
}
Latihan 2: Slice Operations
package main
import "fmt"
func main() {
// TODO: Buat slice angka dari 1-10
// Tampilkan:
// - 3 elemen pertama
// - 3 elemen terakhir
// - elemen tengah (index 4-6)
// - semua elemen genap
}
Latihan 3: Map Operations
package main
import "fmt"
func main() {
// TODO: Buat map untuk menyimpan data siswa
// Key: nama siswa (string)
// Value: nilai (int)
// Tambahkan minimal 5 siswa
// Tampilkan siswa dengan nilai tertinggi dan terendah
}
Latihan 4: Struct dan Method
package main
import "fmt"
// TODO: Buat struct Book dengan field:
// - Title (string)
// - Author (string)
// - Pages (int)
// - Price (float64)
// TODO: Buat method untuk struct Book:
// - Info() string: return informasi lengkap buku
// - IsExpensive() bool: return true jika harga > 100000
func main() {
// TODO: Buat beberapa instance Book
// Test semua method yang sudah dibuat
}
Kesimpulan
Data types adalah fondasi dari programming di Go. Poin-poin penting:
- Go memiliki sistem type yang kuat dan static
- Basic types: int, float, bool, string
- Composite types: array, slice, map, struct
- Reference types: pointer, interface, function, channel
- Setiap type memiliki zero value yang aman
- Type conversion harus dilakukan secara eksplisit
- Interface memberikan fleksibilitas dan polymorphism
Dengan memahami berbagai data type di Go, kita dapat memilih type yang tepat untuk kebutuhan program dan menulis kode yang efisien serta mudah dipelihara. Di bab selanjutnya, kita akan belajar tentang operators dan expressions untuk memanipulasi data-data ini.