Metode ekstensi memungkinkan Anda menambahkan fungsi baru ke tipe yang sudah ada dan tipe dari pustaka pihak ketiga tanpa mengubah kode sumber kelas asli. Pelengkapan otomatis IDE akan menampilkan metode ekstensi bersama metode bawaan tipe.
Anda tidak bisa mengubah API yang disediakan pihak lain, namun ingin menambahkan metode utilitas praktis.
Contoh kebutuhan: gunakan '42'.parseInt() alih-alih int.parse('42').
Struktur sintaks
extension NamaEkstensi? on TipeTarget {
// Metode, getter, setter, operator, anggota statis
}Code language: JavaScript (javascript)
Contoh
// Letakkan semua kode dalam satu berkas, tidak perlu dipisah, main langsung dieksekusi
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
void main() {
print('42'.parseInt()); // 42
print('3.14'.parseDouble()); // 3.14
print('100'.padLeft(6)); // Perbandingan dengan metode bawaan String
}Code language: Dart (dart)
Hasil eksekusi
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
42
3.14
100Code language: CSS (css)
Nama ekstensi bersifat opsional; this merujuk pada instance yang memanggil ekstensi.
Jenis anggota yang didukung dalam ekstensi
Dalam sebuah ekstensi, Anda dapat mendefinisikan: metode instance, getter, setter, operator dan anggota statis.
extension StringExt on String {
// getter
bool get isEmptyOrBlank => trim().isEmpty;
// Metode instance
String repeat(int count) => List.filled(count, this).join();
// Overload operator
String operator *(int count) => repeat(count);
// Anggota statis (diakses melalui nama ekstensi)
static String emptyStr = '';
static void printTip() => print("Metode statis dari ekstensi string");
}
void main() {
var str = " dart ";
print(str.isEmptyOrBlank);
print("hi" * 3);
print("hello".repeat(2));
// Akses anggota statis
print(StringExt.emptyStr);
StringExt.printTip();
}Code language: PHP (php)
Hasil eksekusi
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
false
hihihi
hellohello
Metode statis dari ekstensi stringCode language: CSS (css)
Ekstensi tanpa nama (ekstensi anonim)
Jika nama ekstensi tidak ditentukan, ekstensi hanya terlihat di pustaka saat ini. Konflik nama tidak dapat diselesaikan dengan pemanggilan eksplisit.
Tidak bisa dipanggil dari luar dengan sintaks NamaEkstensi(instance).
extension on String {
bool get isBlank => trim().isEmpty;
}
void main() {
print(" ".isBlank); // true
}Code language: Dart (dart)
Anggota statis pada ekstensi anonim hanya dapat digunakan di dalam ekstensi itu sendiri.
Ekstensi generik (Generic extensions)
Anda dapat membuat ekstensi untuk tipe generik seperti List<T>
extension MyFancyList<T> on List<T> {
int get doubleLength => length * 2;
List<T> operator -() => reversed.toList();
List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}
void main() {
List<int> list = [1, 2, 3, 4];
print(list.doubleLength); // 8
print(-list); // [4,3,2,1]
print(list.split(2)); // [[1,2],[3,4]]
}Code language: Dart (dart)
Hasil eksekusi
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
8
[4, 3, 2, 1]
[[1, 2], [3, 4]]Code language: CSS (css)
Tipe statis static vs dynamic
Variabel bertipe dynamic tidak dapat memanggil metode ekstensi
Metode ekstensi diselesaikan secara statis. Tipe variabel dynamic baru diketahui saat runtime, sehingga ekstensi tidak dapat ditemukan:
void main() {
dynamic d = '2';
// print(d.parseInt()); // Menimbulkan NoSuchMethodError saat runtime
var v = '2';
print(v.parseInt()); // Tipe disimpulkan sebagai String dan berfungsi normal
}
extension NumberParsing on String {
int parseInt() => int.parse(this);
}Code language: JavaScript (javascript)
Penyebab: Metode ekstensi dihubungkan pada waktu kompilasi berdasarkan tipe statis variabel, bukan pencarian saat program berjalan.
Solusi konflik nama API
Ada tiga solusi jika beberapa ekstensi memiliki anggota dengan nama yang sama.
1: Sembunyikan ekstensi yang berkonflik menggunakan show / hide saat import
// string_apis.dart berisi NumberParsing
// string_apis_2.dart berisi NumberParsing2 yang juga punya metode parseInt
import 'string_apis.dart';
import 'string_apis_2.dart' hide NumberParsing2;
void main() {
print('42'.parseInt()); // Menggunakan implementasi dari string_apis.dart
}Code language: Dart (dart)
2: Pemanggilan eksplisit ekstensi (sintaks pembungkus)
import 'string_apis.dart'; // NumberParsing
import 'string_apis_2.dart'; // NumberParsing2
void main() {
// print('42'.parseInt()); // Konflik, error kompilasi
print(NumberParsing('42').parseInt());
print(NumberParsing2('42').parseInt());
}Code language: Dart (dart)
3: Impor pustaka dengan awalan (prefix)
Gunakan prefix untuk membedakan dua ekstensi dengan nama identik:
import 'string_apis.dart';
import 'string_apis_3.dart' as rad;
void main() {
print(NumberParsing('42').parseInt());
print(rad.NumberParsing('42').parseInt());
// Metode ekstensi tanpa konflik tetap bisa dipanggil secara implisit
print('42'.parseNum());
}Code language: Dart (dart)
Metode ekstensi (Extension methods)