package main

import "fmt"

// Identitas menerima satu type parameter T dengan constraint any.
func Identitas[T any](nilai T) T {
	return nilai
}

// Lebih dari satu type parameter dipisah koma di dalam kurung siku.
func Pasangan[K comparable, V any](kunci K, nilai V) string {
	return fmt.Sprintf("(%v: %v)", kunci, nilai)
}

// Type parameter juga bisa dipakai pada deklarasi tipe.
type Box[T any] struct {
	Nama string
	Isi  T
}

func main() {
	// Instansiasi eksplisit: tipe T disebut langsung di dalam kurung siku.
	fmt.Println(Identitas[int](21))

	// Instansiasi implisit: compiler menyimpulkan T dari argumen.
	fmt.Println(Identitas(21 * 2))

	// Dua type parameter diisi manual.
	fmt.Println(Pasangan[string, float64]("berat", 62.5))

	// K=string dan V=string tersimpulkan dari argumen.
	fmt.Println(Pasangan("kode", "GO-118"))

	// Instansiasi tipe Box dengan dua tipe berbeda.
	kotakAngka := Box[int]{Nama: "stok", Isi: 42}
	kotakTeks := Box[string]{Nama: "pesan", Isi: "halo"}
	fmt.Printf("%s=%d bertipe %T\n", kotakAngka.Nama, kotakAngka.Isi, kotakAngka.Isi)
	fmt.Printf("%s=%s bertipe %T\n", kotakTeks.Nama, kotakTeks.Isi, kotakTeks.Isi)
}
