Generics

Menulis class dan function yang bekerja untuk banyak tipe dengan generics, batasan tipe (extends), dan memahami List<T>, Map<K, V>, serta Future<T>.

Part 12 dari 20 ± 40 menit Gratis

Masalah yang diselesaikan generics

Misalkan kamu butuh kotak yang menyimpan satu benda. Tanpa generics, kamu harus membuat KotakInt, KotakString, KotakBuah, dst. Atau memakai dynamic dan kehilangan keamanan tipe. Generics membuat satu definisi yang berlaku untuk tipe apa pun, dengan tipe tetap terjaga.

Class generik

class Kotak<T> {
  T isi;
  Kotak(this.isi);

  T ambil() => isi;
  void ganti(T baru) => isi = baru;
}

var a = Kotak<int>(5);
var b = Kotak<String>('halo');
int x = a.ambil();             // pasti int
// a.ganti('teks');            // ERROR: harus int

T adalah type parameter: placeholder yang diisi saat class dipakai. Nama lazim: T (type), E (element), K dan V (key dan value). Dart biasanya bisa menebak tipenya: Kotak(5) otomatis Kotak<int>.

Function generik

T pertama<T>(List<T> daftar) => daftar.first;

print(pertama([10, 20]));        // 10
print(pertama(['a', 'b']));      // a

List<T> ulang<T>(T nilai, int kali) => List.filled(kali, nilai);
print(ulang('x', 3));            // [x, x, x]

Batasan tipe dengan extends

Kadang kita hanya ingin menerima tipe tertentu. Pakai extends untuk membatasi:

T terbesar<T extends num>(List<T> daftar) {
  T hasil = daftar.first;
  for (var n in daftar) {
    if (n > hasil) hasil = n;
  }
  return hasil;
}

print(terbesar([3, 9, 2]));          // 9
print(terbesar([1.5, 0.2]));         // 1.5
// terbesar(['a', 'b']);             // ERROR: String bukan num

class Hewan { String get suara => '...'; }
class Penampung<T extends Hewan> {
  final List<T> isi = [];
  void tambah(T h) => isi.add(h);
}

Dengan batasan T extends num, di dalam function kita boleh memakai operator > karena pasti angka.

Generics yang sudah kamu pakai

TipeArti
List<String>Daftar yang elemennya String
Map<String, int>Kunci String, nilai int
Set<double>Himpunan double
Future<int>Nilai int yang akan tersedia nanti (bab 15)
Stream<String>Aliran String dari waktu ke waktu (bab 16)

Contoh: Hasil<T> (sukses atau gagal)

class Hasil<T> {
  final T? data;
  final String? galat;

  const Hasil.sukses(this.data) : galat = null;
  const Hasil.gagal(this.galat) : data = null;

  bool get berhasil => galat == null;
}

Hasil<int> bagi(int a, int b) =>
    b == 0 ? const Hasil.gagal('Dibagi nol') : Hasil.sukses(a ~/ b);

var h = bagi(10, 2);
print(h.berhasil ? h.data : h.galat);    // 5

Pola seperti ini dipakai di aplikasi nyata untuk membungkus hasil jaringan atau validasi tanpa mengandalkan exception.

Typedef: nama pendek untuk tipe panjang

typedef Peta = Map<String, List<int>>;
typedef Pemroses<T> = T Function(T);

Peta data = {'a': [1, 2]};

Error umum

  • The argument type 'String' can't be assigned to the parameter type 'int'. → memasukkan tipe yang salah ke class generik.
  • The operator '>' isn't defined for the type 'T'. → T tidak dibatasi; tambahkan extends num atau Comparable.
  • List tanpa tipe jadi List<dynamic> → tulis tipenya agar compiler dapat membantu.

Praktikkan langsung, gratis

Tulis dan jalankan kode langsung di browser, dapatkan penilaian otomatis. Daftar gratis kapan saja untuk menyimpan progres dan meraih sertifikat.

Coba latihan sekarang, tanpa daftar
Bagikan: WhatsApp Facebook LinkedIn X