Kondisi perulangan menentukan kapan putaran berakhir, tetapi sebagian keadaan menuntut keputusan di tengah putaran. Perl menyediakan tiga pernyataan untuk itu, yaitu last yang menghentikan perulangan seketika, next yang melompat ke putaran berikutnya, dan redo yang mengulang badan perulangan tanpa menilai kembali kondisinya. Tanpa argumen, ketiganya bekerja pada perulangan terdalam yang mengapitnya, sedangkan label memperluas jangkauannya ke perulangan luar. Topik ini membahas keempatnya beserta contoh yang seluruh putarannya berhingga.
Menghentikan perulangan dengan last#
Pernyataan last menghentikan perulangan yang mengapitnya seketika, dan eksekusi berlanjut pada pernyataan pertama setelah blok perulangan. Pernyataan ini tepat untuk pencarian yang boleh berhenti begitu jawabannya ditemukan, karena putaran setelahnya tidak perlu dijalankan lagi.
Skrip berikut mencari kelipatan 7 pertama pada lima angka berurutan.
use strict;
use warnings;
my @angka = (41, 42, 43, 44, 45);
foreach my $angka (@angka) {
if ($angka % 7 == 0) {
print "Kelipatan 7 pertama ditemukan: $angka\n";
last;
}
print "$angka belum kelipatan 7\n";
}41 belum kelipatan 7
Kelipatan 7 pertama ditemukan: 42Angka 41 diproses dan dilaporkan belum kelipatan 7, kemudian angka 42 memenuhi kondisi sehingga last tereksekusi. Angka 43 sampai 45 tidak pernah diproses meskipun masih tersisa dalam list, karena perulangan sudah ditutup. Tanpa last, pencarian tetap berjalan sampai elemen terakhir dan memboroskan putaran, dan pemborosan itu terasa pada data yang besar. Hasil yang sama dapat diperoleh dengan kondisi terbalik tanpa last, tetapi bentuk last menghindari pemeriksaan yang tidak diperlukan pada putaran setelah jawaban ditemukan.
Pernyataan last lazim dipadukan dengan modifier pernyataan menjadi last if KONDISI ketika pemeriksaannya sederhana. Bentuk ini setara dengan blok if berisi satu pernyataan dan menjaga badan perulangan tetap pendek. last tidak memerlukan argumen apabila yang dituju adalah perulangan terdalam, sedangkan perulangan luar dituju dengan label sebagaimana dibahas pada bagian Label pada perulangan bersarang.
Melompati putaran dengan next#
Pernyataan next menghentikan putaran yang sedang berjalan dan melanjutkan ke putaran berikutnya, yaitu menilai kembali kondisi perulangan atau mengambil elemen list berikutnya. Sisa pernyataan pada badan setelah next dilewati seluruhnya. Pernyataan ini tepat untuk menyaring data, yaitu melewatkan baris yang tidak memenuhi syarat dan mengolah sisanya.
Contoh klasiknya adalah menyaring baris data. Skrip berikut mengolah catatan suhu yang memuat baris komentar yang diawali karakter #, baris kosong, dan baris berisi angka. Dua pernyataan next membuang baris yang tidak layak diolah, sedangkan baris angka dicatat ke dalam total. Fungsi substr($baris, 0, 1) mengambil karakter pertama dari baris, sehingga baris komentar dikenali tanpa ekspresi reguler.
use strict;
use warnings;
my @baris = (
'# catatan suhu ruang, satuan derajat celsius',
'26',
'',
'28',
'# pencatatan selesai',
'25',
'27',
);
my $total = 0;
my $jumlah = 0;
foreach my $baris (@baris) {
next if $baris eq '';
next if substr($baris, 0, 1) eq '#';
print "Dicatat: $baris\n";
$total += $baris;
$jumlah += 1;
}
print "Pengukuran tercatat: $jumlah\n";
print "Total suhu: $total\n";Dicatat: 26
Dicatat: 28
Dicatat: 25
Dicatat: 27
Pengukuran tercatat: 4
Total suhu: 106Dari tujuh baris data, empat baris lolos penyaringan, sedangkan dua baris komentar dan satu baris kosong dibuang. Letak next di awal badan perulangan merupakan praktik yang efisien, karena syarat penolakan diperiksa sebelum pekerjaan lain dijalankan. Pola ini mudah diperluas, misalnya menambahkan batas atas suhu dengan satu pernyataan next lagi sebelum baris dicatat.
Pada for gaya C, next tetap menjalankan bagian langkah penghitungnya sebelum menilai kondisi kembali, sehingga penghitung tidak tertahan pada nilai yang sama. Perilaku ini berbeda dengan redo, yang tidak menyentuh kondisi sama sekali sebagaimana dibahas pada bagian Mengulang badan dengan redo.
Mengulang badan dengan redo#
Pernyataan redo mengulang badan perulangan dari awal tanpa menilai kembali kondisinya. Perilaku ini membedakannya dari next, yang menilai kembali kondisi sebelum putaran berikutnya, dan dari last, yang keluar dari perulangan. Pemakaian redo yang wajar adalah mengulang satu putaran yang gagal, misalnya meminta ulang data yang belum valid, karena kondisi perulangan biasanya didorong oleh sumber data yang tidak berubah di tengah putaran.
Skrip berikut menunjukkan mekanismenya dengan aman. Penghitung ditambahkan pada kondisi itu sendiri melalui penaikan prafiks ++$evaluasi, dan satu bendera memastikan redo hanya terjadi sekali.
use strict;
use warnings;
my $evaluasi = 0;
my $sudah_redo = 0;
while (++$evaluasi <= 3) {
print "badan dijalankan, evaluasi ke-$evaluasi\n";
if ($evaluasi == 2 && $sudah_redo == 0) {
$sudah_redo = 1;
print "badan diulang tanpa evaluasi kondisi\n";
redo;
}
}
print "Selesai, kondisi dievaluasi $evaluasi kali\n";badan dijalankan, evaluasi ke-1
badan dijalankan, evaluasi ke-2
badan diulang tanpa evaluasi kondisi
badan dijalankan, evaluasi ke-2
badan dijalankan, evaluasi ke-3
Selesai, kondisi dievaluasi 4 kaliBaris pertama dan kedua berasal dari evaluasi kondisi pertama dan kedua. Setelah redo tereksekusi, badan langsung dijalankan lagi tanpa evaluasi kondisi baru, dan karena penghitung hanya ditambahkan pada kondisi, nilai $evaluasi tetap 2 sehingga baris evaluasi ke-2 tercetak dua kali. Kondisi dinilai empat kali secara total, tiga kali bernilai benar dan satu kali mengakhiri perulangan, sedangkan badan dijalankan empat kali untuk tiga putaran yang berbeda.
Perlakukan redo sebagai alat yang jarang digunakan. Pastikan selalu ada keadaan yang berubah sebelum redo tereksekusi lagi, misalnya bendera sekali pakai atau penghitung tambahan. Pilih next apabila kondisi memang seharusnya dinilai kembali di antara putaran.
Label pada perulangan bersarang#
Tanpa argumen, last dan next bekerja pada perulangan terdalam yang mengapitnya. Perulangan bersarang sering menuntut sebaliknya, misalnya menghentikan pencarian dua dimensi sekaligus. Label memberi nama pada sebuah perulangan sehingga last, next, dan redo dapat menunjuk perulangan tertentu secara eksplisit. Label ditulis sebagai kata berhuruf kapital semua yang diikuti titik dua, tepat sebelum kata kunci perulangannya, misalnya LUAR:, dan konvensi huruf kapital membuat label mudah dibedakan dari nama variabel.
# tidak-dijalankan
LABEL: while (KONDISI) {
PERNYATAAN
last LABEL if KONDISI_LAIN;
}Skrip berikut mencari pasangan angka dalam rentang 1 sampai 4 yang hasil perkaliannya 12, dengan perulangan luar berlabel LUAR.
use strict;
use warnings;
LUAR: for my $i (1 .. 4) {
for my $j (1 .. 4) {
my $hasil = $i * $j;
if ($hasil == 12) {
print "$i x $j = 12, pencarian dihentikan\n";
last LUAR;
}
print "$i x $j = $hasil\n";
}
}1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
1 x 4 = 4
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12, pencarian dihentikanPerulangan dalam menelusuri setiap pasangan angka, dan begitu $hasil bernilai 12, pernyataan last LUAR menutup perulangan luar sehingga putaran $i berikutnya tidak pernah dijalankan. Tanpa label, last hanya menutup perulangan dalam dan pencarian berlanjut ke $i berikutnya, karena perulangan luar tidak tahu bahwa jawabannya sudah ditemukan. Bentuk next LUAR dan redo LUAR juga sah dan menunjuk perulangan yang berlabel sama.
Gunakan label seperlunya. Kontrol yang menyeberangi banyak tingkat perulangan mengurangi keterbacaan, sehingga logika yang makin rumit lebih baik ditata ulang, misalnya dengan memindahkan sebagian permasalahannya ke subrutin.
Kesalahan umum#
Kesalahan pertama adalah mengharapkan last menutup seluruh perulangan bersarang. Tanpa label, pernyataan tersebut hanya menutup perulangan terdalam, sehingga pencarian yang seharusnya berhenti tetap berlanjut pada putaran luar. Perbaikannya adalah memberi label pada perulangan luar dan menulis last LABEL dengan label yang sama.
Kesalahan kedua adalah redo yang tidak disertai perubahan keadaan. Kondisi tidak dinilai kembali sebelum badan diulang, sehingga putaran berjalan tanpa henti dan program macet. Perbaikannya adalah mengubah keadaan sebelum redo tereksekusi lagi, misalnya dengan bendera sekali pakai atau penghitung tambahan seperti pada contoh di bagian Mengulang badan dengan redo. Bendera sekali pakai berarti variabel yang diubah satu kali saja, sehingga putaran ulang hanya terjadi sebanyak yang direncanakan.
Kesalahan ketiga adalah menempatkan last, next, atau redo di luar blok perulangan. Perl melaporkan error Can't "last" outside a loop block karena ketiga pernyataan tersebut bergantung pada perulangan yang mengapitnya. Perbaikannya adalah memindahkan pernyataan ke dalam blok perulangan yang dimaksud, kemudian memeriksa kembali kurung kurawal apabila blok ternyata tertutup lebih awal.
Ringkasan#
lastmenghentikan perulangan seketika dan tepat untuk pencarian yang boleh berhenti pada jawaban pertama.nextmelewatkan sisa badan menuju putaran berikutnya, sehingga tepat untuk menyaring baris data.redomengulang badan tanpa menilai kembali kondisi, sehingga memerlukan keadaan yang berubah agar putarannya berhingga.- Tanpa argumen, ketiga pernyataan bekerja pada perulangan terdalam, sedangkan
last LABEL,next LABEL, danredo LABELmenunjuk perulangan berlabel.
Referensi#
- perlsyn — perldoc.perl.org
— Dokumentasi resmi sintaks Perl yang mencakup
last,next,redo, serta label perulangan. - perlintro — perldoc.perl.org — Pengantar resmi Perl yang memperkenalkan pernyataan pengendali perulangan secara ringkas.