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>.
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
| Tipe | Arti |
|---|---|
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'.→Ttidak dibatasi; tambahkanextends numatauComparable.- List tanpa tipe jadi
List<dynamic>→ tulis tipenya agar compiler dapat membantu.