Keanggotaan dan penghapusan entri hash dikelola oleh dua fungsi berpasangan, yaitu exists untuk menguji keberadaan kunci dan delete untuk menghapus entrinya. Keduanya penting karena hash boleh menyimpan kunci dengan nilai undef, sehingga sekadar membaca nilai tidak cukup untuk mengetahui apakah sebuah kunci tercatat. Topik ini membahas perbedaan antara kunci yang tidak ada, kunci bernilai undef, dan nilai yang belum terisi, beserta peringatan yang muncul ketika nilai undef ikut dicetak.
Menguji keanggotaan kunci dengan exists#
Fungsi exists $hadir{Budi} menguji apakah kunci Budi tercatat pada hash, tanpa memandang isi nilainya. Hasilnya berupa nilai benar atau salah yang langsung digunakan pada percabangan if. Bentuk kebalikannya ditulis if (not exists ...), sebagaimana pemeriksaan kunci Dewi pada skrip berikut.
Pembeda yang penting adalah kunci yang nilainya undef. Penugasan $hadir{Eko} = undef tetap mencatat kunci Eko, sehingga exists tetap menghasilkan benar, sedangkan fungsi defined menguji nilainya dan menghasilkan salah. Dengan demikian, exists menjawab pertanyaan apakah kunci tercatat, sedangkan defined menjawab pertanyaan apakah nilai kunci tersebut terisi. Keduanya saling melengkapi, dan penggunaan keduanya secara tertukar merupakan sumber kesalahan yang halus pada program yang datanya berasal dari luar skrip. Nilai 1 pada hash kehadiran hanyalah penanda bahwa peserta tercatat, dan isi angkanya tidak digunakan dalam pengujian.
Pengujian exists dan pembacaan nilai sama-sama tidak menciptakan entri baru, sehingga hash tetap utuh setelah keduanya diterapkan pada kunci yang belum tercatat. Entri baru hanya muncul pada saat penulisan nilai, sebagaimana penugasan undef pada skrip di atas yang mencatat kunci Eko. Kunci hash disimpan sebagai string, sehingga nilai apa pun yang digunakan sebagai kunci dikonversi menjadi teks lebih dahulu. Bentuk negasinya juga tidak terbatas pada not, karena if (! exists $hadir{Dewi}) memberikan hasil yang sama, dan pemilihan bentuknya merupakan soal konsistensi gaya dalam satu skrip.
use strict;
use warnings;
# daftar kehadiran peserta pelatihan
my %hadir = (
Ali => 1,
Budi => 1,
Citra => 1,
);
# exists menguji apakah kunci tercatat pada hash
if (exists $hadir{Budi}) {
print "Budi tercatat hadir\n";
}
if (not exists $hadir{Dewi}) {
print "Dewi tidak tercatat\n";
}
# kunci yang nilainya undef tetap dianggap ada oleh exists
$hadir{Eko} = undef;
if (exists $hadir{Eko}) {
print "Eko tercatat, nilainya undef\n";
}
# defined menguji nilai, bukan keberadaan kunci
if (not defined $hadir{Eko}) {
print "Nilai Eko belum terisi\n";
}Budi tercatat hadir
Dewi tidak tercatat
Eko tercatat, nilainya undef
Nilai Eko belum terisiNilai kunci yang tidak ada dan peringatannya#
Membaca kunci yang tidak tercatat pada hash tidak menghentikan program. Ekspresi $stok{buku} pada hash tanpa kunci buku menghasilkan undef secara diam-diam, karena pembacaan tidak dianggap sebagai kesalahan. Peringatan baru muncul ketika nilai undef itu ikut digunakan, misalnya diinterpolasi ke dalam string untuk dicetak. Dengan use warnings aktif, Perl menampilkan pesan Use of uninitialized value beserta nama variabelnya, sedangkan program tetap berjalan dan bagian yang kosong dicetak sebagai string kosong.
Peraga berikut menunjukkan peringatan tersebut pada hash persediaan yang tidak memiliki kunci buku.
# peraga peringatan ketika kunci hash yang tidak ada ikut dicetak
perl -e 'use strict; use warnings; my %stok = (pensil => 24); print "Stok buku: [$stok{buku}]\n";' 2>&1Use of uninitialized value $stok{"buku"} in concatenation (.) or string at -e line 1.
Stok buku: []Program tetap mencetak baris kedua, sehingga perilaku ini mudah luput bila keluaran tidak diperiksa. Perbaikannya bukan menghilangkan use warnings, melainkan menguji kuncinya lebih dahulu. Pencetakan langsung diganti dengan pemeriksaan exists $stok{buku} sebelum mencetak, atau dengan nilai cadangan apabila kunci tidak ada. Dengan disiplin ini, peringatan uninitialized value menjadi sinyal yang jarang muncul, sehingga setiap kemunculannya layak ditelusuri sampai akarnya.
Pesan peringatan itu memuat nama variabel lengkap dengan berkas dan baris kejadiannya, sehingga sumbernya dapat ditelusuri tanpa menebak. Frasa in concatenation (.) or string muncul karena interpolasi string dikompilasi sebagai penyambungan, sehingga Perl melaporkannya pada operasi yang sama. Untuk memberi nilai cadangan tanpa percabangan, operator defined-or // mengembalikan nilai di sebelah kanannya apabila nilai di sebelah kirinya belum terisi. Penulisan $stok{buku} // 0 menghasilkan 0 alih-alih memicu peringatan. Operator ini berbeda dari ||, karena || juga mengganti nilai 0 dan string kosong yang sah, sedangkan // hanya bereaksi atas undef.
Menghapus entri dengan delete#
Fungsi delete $stok{penghapus} menghapus pasangan kunci dan nilai sekaligus, lalu mengembalikan nilai yang terhapus. Setelah penghapusan, kunci tersebut tidak lagi ditemukan oleh exists, dan scalar(keys %stok) berkurang satu. Perilaku ini berbeda dengan penugasan $stok{penghapus} = undef, yang hanya mengosongkan nilai tetapi tetap meninggalkan kuncinya tercatat. Apabila maksudnya benar-benar mencabut entri, delete merupakan pilihannya.
delete pada kunci yang memang tidak tercatat tidak memicu peringatan dan hanya mengembalikan undef, sehingga penghapusan atas kunci yang mungkin sudah tidak ada dapat ditulis tanpa pengujian lebih dahulu. Pada skrip berikut, kunci penggaris tidak pernah ada, dan hasil delete-nya diuji dengan defined agar keluarannya menampilkan kata undef.
use strict;
use warnings;
# persediaan alat tulis
my %stok = (
pensil => 24,
buku => 10,
penghapus => 7,
);
# delete menghapus entri dan mengembalikan nilai yang terhapus
my $dihapus = delete $stok{penghapus};
print "Nilai terhapus : $dihapus\n";
# kunci yang sudah dihapus tidak lagi ditemukan oleh exists
if (not exists $stok{penghapus}) {
print "Entri penghapus sudah tidak ada\n";
}
# delete pada kunci yang tidak tercatat mengembalikan undef tanpa peringatan
my $hasil = delete $stok{penggaris};
print "Hasil penggaris: ", (defined $hasil ? $hasil : "undef"), "\n";
print "Banyak entri : ", scalar(keys %stok), "\n";Nilai terhapus : 7
Entri penghapus sudah tidak ada
Hasil penggaris: undef
Banyak entri : 2Nilai balik penghapusan berguna untuk pencatatan, misalnya menyimpan nilai yang dicabut sebelum entrinya dihilangkan dari hash. Setelah kedua operasi pada skrip, hash hanya memuat kunci pensil dan buku, sebagaimana terlihat pada penghitungan terakhirnya. Pola uji exists sebelum penghapusan tetap sah, tetapi menjadi pilihan gaya dan bukan keharusan, karena delete sendiri sudah aman pada kunci yang tidak ada.
Kesalahan umum#
- Menggunakan pembacaan nilai sebagai uji keanggotaan kunci. Kunci yang nilainya
undeftetap tercatat, sehinggaif ($hadir{Eko})memperlakukan kunci tercatat itu sama dengan kunci yang tidak ada. Perbaikannya menggunakanexists $hadir{Eko}apabila yang ditanya adalah keberadaan kunci, dandefined $hadir{Eko}apabila yang ditanya adalah isi nilainya. - Mencetak nilai kunci yang belum terisi tanpa pemeriksaan terlebih dahulu. Nilai
undefyang diinterpolasi memicu peringatanUse of uninitialized value, sedangkan program tetap berjalan dengan bagian kosong yang mudah luput. Perbaikannya menguji kunci denganexistslebih dahulu atau menyediakan nilai cadangan melalui operator//. - Mengira penugasan
undefmencabut entri hash. Kunci tetap tercatat setelah$stok{penghapus} = undef, sehinggaexiststetap benar danscalar(keys %stok)tidak berkurang. Perbaikannya menggunakandelete $stok{penghapus}apabila entrinya harus benar-benar dihapus dari hash.
Ringkasan#
exists $hash{kunci}menguji keberadaan kunci dan tetap benar untuk kunci yang nilainyaundef.definedmenguji isi nilai, sehingga kunci yang tercatat tetapi belum terisi dapat dibedakan dari kunci yang tidak ada.- Membaca kunci yang tidak ada menghasilkan
undeftanpa peringatan, sedangkan pencetakannya memicu peringatanuninitialized value. deletemenghapus entri beserta mengembalikan nilainya, tidak memicu peringatan pada kunci yang tidak ada, dan berbeda dari penugasanundef.
Referensi#
- perlfunc — Perl documentation
— Daftar fungsi bawaan Perl, termasuk
exists,delete, dandefined. - perldata — Perl documentation
— Menguraikan perilaku nilai
undefdan keberadaan kunci pada hash.