Terkadang saya membutuhkan loop yang membutuhkan istirahat seperti ini:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Saya merasa tidak nyaman dengan tulisan
if(condition){
break;
}
karena mengkonsumsi 3 baris kode. Dan saya menemukan loop dapat ditulis ulang sebagai:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Jadi pertanyaan saya adalah, apakah praktik yang baik untuk memindahkan kondisi ke bidang kondisi untuk mengurangi garis kode jika mungkin?
coding-style
loops
ocomfd
sumber
sumber
condition
khususnya.for(int i=0;i<array.length && !condition;i++)
relatif tidak umum dan dapat diabaikan oleh seseorang yang hanya membaca kode; ini mungkin kasus penggunaan yang baik untuk awhile
ataudo while
loop, yang lebih sering memiliki beberapa kondisi break dalam definisi loop.Jawaban:
Dua contoh yang Anda berikan tidak setara secara fungsional. Dalam aslinya, pengujian kondisi dilakukan setelah bagian "kode lain", sedangkan dalam versi yang dimodifikasi, dilakukan terlebih dahulu, pada awal tubuh loop.
Kode tidak boleh ditulis ulang dengan tujuan mengurangi jumlah baris. Jelas itu adalah bonus yang bagus ketika berhasil seperti itu, tetapi itu tidak boleh dilakukan dengan mengorbankan keterbacaan atau kebenaran.
sumber
Saya tidak membeli argumen bahwa "ia mengkonsumsi 3 baris kode" dan karenanya buruk. Bagaimanapun, Anda bisa menuliskannya sebagai:
dan hanya mengkonsumsi satu baris.
Jika
if
muncul setengah jalan melalui loop, tentu saja harus ada sebagai tes terpisah. Namun, jika tes ini muncul di akhir blok, Anda telah membuat loop yang memiliki tes melanjutkan di kedua ujung loop, mungkin menambah kompleksitas kode. Berhati-hatilah, bahwa terkadangif (condition)
tes hanya masuk akal setelah blok dijalankan.Tetapi dengan asumsi itu tidak terjadi, dengan mengadopsi pendekatan lain:
kondisi keluar disimpan bersama, yang dapat menyederhanakan banyak hal (terutama jika " beberapa kode lain " panjang).
Tidak ada jawaban yang tepat di sini, tentu saja. Jadi berhati-hatilah dengan idiom bahasa tersebut, seperti apa konvensi pengkodean tim Anda, dll. Tetapi secara seimbang, saya akan mengadopsi pendekatan uji tunggal ketika masuk akal secara fungsional untuk melakukannya.
sumber
Pertanyaan semacam ini telah memicu perdebatan hampir selama pemrograman berjalan. Untuk melemparkan topi saya ke atas ring, saya akan memilih versi dengan
break
syarat dan inilah alasannya (untuk kasus khusus ini):The
for
loop hanya ada untuk menentukan nilai-nilai iterasi dalam lingkaran. Pengkodean kondisi melanggar dalam yang hanya mengacaukan logika IMO.Memiliki terpisah
break
membuatnya sangat jelas bahwa selama pemrosesan normal, nilai-nilai seperti yang ditentukan dalamfor
loop dan pemrosesan harus dilanjutkan kecuali di mana kondisi tersebut masuk.Sebagai sedikit latar belakang, saya mulai coding a
break
, kemudian meletakkan kondisi dalamfor
loop selama bertahun-tahun (di bawah arahan seorang programmer luar biasa) dan kemudian kembali kebreak
gaya karena hanya terasa jauh lebih bersih (dan merupakan gaya yang berlaku di berbagai buku tebal kode yang saya konsumsi).Ini adalah salah satu dari perang suci tersebut pada akhir hari - beberapa orang mengatakan Anda tidak boleh keluar dari loop secara artifisial, jika tidak itu bukan loop nyata. Lakukan apa pun yang menurut Anda dapat dibaca (baik untuk diri sendiri dan orang lain). Jika mengurangi penekanan tombol benar-benar sesuai keinginan Anda, main golf kode di akhir pekan - bir opsional.
sumber
for
loop digunakan ketika jumlah iterasi diketahui (misalnya ketika tidak ada kondisi kerusakan kecuali akhir array / daftar) danwhile
kapan tidak. Ini tampaknya menjadi kasus untukwhile
loop. Jika keterbacaan menjadi perhatian, bagianidx+=1
dalam loop jauh lebih bersih untuk dibaca daripada satuif/else
blokfor(int i=0; i<something;i++)
loop sehingga saya kira separuh pengembang tidak begitu ingat bahwafor
loop dapat digunakan secara berbeda, dan karenanya sulit memahami&&condition
bagian tersebut.for(;;)
...for
loop adalah untuk iterasi lebih dari sesuatu 1 - mereka tidak hanya lol-mari-tarik-beberapa-hal-acak-dari-tubuh-dan-menempatkan-mereka-di-loop-header - tiga ekspresi memiliki sangat arti khusus:Idenya adalah untuk memisahkan penanganan iterasi ( cara mengulang) dari logika di dalam loop ( apa yang harus dilakukan di setiap iterasi). Banyak bahasa biasanya memiliki untuk-setiap loop yang membebaskan Anda dari rincian iterasi, tetapi bahkan jika bahasa Anda tidak memiliki konstruksi itu, atau jika itu tidak dapat digunakan dalam skenario Anda - Anda masih harus membatasi header loop untuk penanganan iterasi.
Jadi, Anda perlu bertanya pada diri sendiri - apakah kondisi Anda tentang penanganan iterasi atau tentang logika di dalam loop? Kemungkinannya, ini tentang logika di dalam loop - jadi harus diperiksa di dalam loop daripada di header.
1 Berbeda dengan loop lain, itu "menunggu" sesuatu terjadi. A
for
/foreach
loop harus memiliki konsep "daftar" item untuk diulangi - bahkan jika daftar itu malas atau tidak terbatas atau abstrak.sumber
someFunction(array[i])
. Sekarang kedua bagian dari kondisi tersebut adalah tentang hal yang Anda iterasi, dan masuk akal untuk menggabungkannya dengan&&
header loop.for
loop pada hati adalah counter, bukan loop atas daftar, dan ini didukung oleh sintaksfor
dalam bahasa sebelumnya (bahasa ini sering memilikifor i = 1 to 10 step 2
sintaks, danstep
perintah - bahkan memungkinkan nilai awal yang bukan indeks dari yang pertama elemen - petunjuk pada konteks numerik, bukan konteks daftar). Satu- satunya kasus penggunaan yang saya pikir mendukungfor
loop sebagai hanya iterasi pada daftar adalah paralelisasi, dan yang memerlukan sintaks eksplisit sekarang pula agar tidak melanggar kode melakukan, misalnya, semacam.Saya sarankan menggunakan versi dengan
if (condition)
. Ini lebih mudah dibaca dan lebih mudah untuk di-debug. Menulis 3 baris kode tambahan tidak akan merusak jari Anda, tetapi akan memudahkan orang berikutnya untuk memahami kode Anda.sumber
naming things
dengan benar untuk memahami apa yang terjadi dan ketika kondisi terputus terpenuhi.Jika Anda mengulangi koleksi di mana elemen-elemen tertentu harus dilewati, maka saya merekomendasikan opsi baru:
Baik Java dan C # membuat ini relatif sepele untuk dilakukan. Saya tidak akan terkejut jika C ++ memiliki cara membuat iterator yang bagus untuk melewati elemen tertentu yang tidak berlaku. Tetapi ini hanya benar-benar pilihan jika bahasa pilihan Anda mendukungnya, dan alasan Anda menggunakannya
break
adalah karena ada kondisi apakah Anda memproses suatu elemen atau tidak.Kalau tidak, ada alasan yang sangat bagus untuk menjadikan kondisi Anda bagian dari for loop - dengan anggapan evaluasi awal itu benar.
Saya telah bekerja pada kode di mana for for loop Anda mengambil beberapa ratus baris dengan beberapa persyaratan dan beberapa matematika kompleks terjadi di sana. Masalah yang Anda hadapi adalah:
break
perintah yang terkubur dalam logika sulit ditemukan dan terkadang mengejutkanDalam situasi itu saya merekomendasikan pedoman berikut dalam urutan pilihan:
break
jika mungkinbreak
di atas loop jika memungkinkanPedoman ini selalu tunduk pada kebenaran kode Anda. Pilih opsi yang paling mewakili niat dan tingkatkan kejelasan kode Anda.
sumber
continue
pernyataan, tapi saya tidak melihat bagaimana mereka banyak membantubreak
.takeWhile
Filter dapat menggantikanbreak
pernyataan. Jika Anda memiliki satu - Java misalnya hanya membuat mereka di Jave 9 (tidak bahwa itu yang sulit untuk mengimplementasikan sendiri)Saya sangat menyarankan untuk mengambil pendekatan yang paling tidak mengejutkan kecuali Anda mendapatkan manfaat yang signifikan dengan melakukan sebaliknya.
Orang tidak membaca setiap huruf ketika membaca sebuah kata, dan mereka tidak membaca setiap kata saat membaca buku - jika mereka mahir membaca, mereka melihat garis besar kata dan kalimat dan membiarkan otak mereka mengisi sisanya. .
Jadi kemungkinan pengembang sesekali akan menganggap ini hanya standar untuk loop dan bahkan tidak melihatnya:
Jika Anda ingin menggunakan gaya itu, saya sarankan mengubah bagian-bagiannya
for(int i=0;i<
dan;i++)
memberi tahu otak pembaca bahwa ini adalah standar untuk loop.Alasan lain untuk ikut
if
-break
adalah bahwa Anda tidak selalu dapat menggunakan pendekatan Anda denganfor
-condition. Anda harus menggunakanif
-break
ketika kondisi break terlalu rumit untuk disembunyikan dalamfor
pernyataan, atau bergantung pada variabel yang hanya dapat diakses di dalamfor
loop.Jadi, jika Anda memutuskan untuk pergi bersama
if
-break
, Anda terlindungi. Tetapi jika Anda memutuskan untuk menggunakanfor
-conditions, Anda harus menggunakan campuranif
-break
danfor
-conditions. Agar konsisten, Anda harus memindahkan kondisi bolak-balik antarafor
-kondisi danif
-break
setiap kali kondisi berubah.sumber
Transformasi Anda mengasumsikan bahwa apa pun
condition
yang dievaluasitrue
saat Anda memasuki loop. Kami tidak dapat mengomentari kebenaran dalam hal ini karena ini tidak didefinisikan.Setelah berhasil "mengurangi baris kode" di sini, Anda dapat melanjutkan untuk melihat
dan menerapkan transformasi yang sama, tiba di
Yang merupakan transformasi tidak valid, karena Anda sekarang tanpa syarat melakukan di
further code
mana Anda sebelumnya tidak.Skema transformasi yang jauh lebih aman adalah mengekstraksi
some other code
dan mengevaluasicondition
ke fungsi terpisahsumber
TL; DR Lakukan apa pun yang paling baik dibaca dalam keadaan khusus Anda
Mari kita ambil contoh ini:
Dalam hal ini kita tidak ingin salah satu kode di dalam for loop dijalankan jika
something
itu benar, jadi memindahkan tessomething
ke bidang kondisi adalah wajar.Kemudian lagi, tergantung pada apakah
something
dapat diaturtrue
sebelum loop, tetapi tidak di dalamnya, ini bisa menawarkan lebih banyak kejelasan:Sekarang bayangkan ini:
Kami mengirim pesan yang sangat jelas di sana. Jika
something
menjadi true saat memproses array maka abaikan seluruh operasi pada titik ini. Untuk memindahkan cek ke bidang kondisi yang perlu Anda lakukan:Bisa dibilang, "pesan" telah menjadi keruh, dan kami sedang memeriksa kondisi kegagalan di dua tempat - bagaimana jika kondisi kegagalan berubah dan kami lupa salah satu tempat?
Tentu saja ada banyak bentuk berbeda untuk loop dan kondisi, semua dengan nuansa mereka sendiri.
Tulis kode sehingga terbaca dengan baik (ini jelas agak subyektif) dan ringkas. Di luar seperangkat pedoman pengkodean yang kejam, semua "aturan" memiliki pengecualian. Tulis apa yang Anda rasa paling baik mengekspresikan pengambilan keputusan, dan meminimalkan peluang kesalahan di masa depan.
sumber
Meskipun mungkin menarik karena Anda melihat semua kondisi di header loop dan
break
mungkin membingungkan di dalam blok besar,for
loop adalah pola di mana sebagian besar programmer mengharapkan perulangan pada rentang tertentu.Terutama karena Anda melakukannya, menambahkan kondisi istirahat tambahan dapat menyebabkan kebingungan dan lebih sulit untuk melihat apakah itu setara secara fungsional.
Seringkali alternatif yang baik adalah dengan menggunakan a
while
ataudo {} while
loop yang memeriksa kedua kondisi, dengan asumsi array Anda memiliki setidaknya satu elemen.Menggunakan loop yang hanya memeriksa kondisi dan tidak menjalankan kode dari header loop, Anda membuat sangat jelas ketika kondisi diperiksa dan apa kondisi aktual dan apa kode dengan efek samping.
sumber
for(...; i <= n; ...)
) sebenarnya membuat kode lebih sulit untuk dibaca karena saya punya untuk berhenti dan berpikir tentang apa yang terjadi di sini dan mungkin melewatkan kondisi sama sekali pada pass pertama karena saya tidak berharap itu ada di sana. Bagi saya, sebuahfor
loop menyiratkan bahwa Anda melakukan looping pada beberapa rentang, jika ada kondisi keluar khusus itu harus dibuat eksplisit denganif
, atau Anda dapat menggunakan awhile
.Ini buruk, karena kode dimaksudkan untuk dibaca oleh manusia -
for
loop non-idiomatis sering membingungkan untuk dibaca, yang berarti bug lebih mungkin bersembunyi di sini, tetapi kode asli mungkin dapat ditingkatkan sambil tetap mempertahankannya. pendek dan mudah dibaca.Jika yang Anda inginkan adalah menemukan nilai dalam array (contoh kode yang disediakan agak umum, tetapi mungkin juga merupakan pola ini), Anda bisa secara eksplisit mencoba menggunakan fungsi yang disediakan oleh bahasa pemrograman khusus untuk tujuan itu. Misalnya (pseudo-code, karena bahasa pemrograman tidak ditentukan, solusinya bervariasi tergantung pada bahasa tertentu).
Ini seharusnya mempersingkat solusi sambil menyederhanakannya ketika kode Anda mengatakan secara spesifik apa yang Anda butuhkan.
sumber
Beberapa alasan menurut saya yang mengatakan, Anda tidak boleh.
do...while
loop (tidakwhile
) karena kondisinya diperiksa setelah beberapa eksekusi kode.Tapi di atas itu, pertimbangkan ini,
Sekarang, dapatkah Anda benar-benar mencapainya dengan menambahkan kondisi ini ke dalam
for
kondisi itu?sumber
Saya pikir menghapus
break
bisa menjadi ide yang bagus, tetapi tidak untuk menyimpan baris kode.Keuntungan dari menulis tanpa itu
break
adalah bahwa post-kondisi loop jelas dan eksplisit. Ketika Anda menyelesaikan loop dan menjalankan baris berikutnya dari program, kondisi loop Andai < array.length && !condition
pasti salah. Karena itu,i
lebih besar dari atau sama dengan panjang array Anda, ataucondition
benar.Dalam versi dengan
break
, ada gotcha yang tersembunyi. Kondisi loop mengatakan bahwa loop berakhir ketika Anda telah menjalankan beberapa kode lain untuk setiap indeks array yang valid, tetapi sebenarnya adabreak
pernyataan yang dapat menghentikan loop sebelum itu, dan Anda tidak akan melihatnya kecuali Anda meninjau kode loop dengan sangat hati-hati. Dan penganalisa statis otomatis, termasuk pengoptimal pengoptimal, dapat mengalami kesulitan mendeduksi seperti apa kondisi post-loop juga.Ini adalah alasan asli Edgar Dijkstra menulis "Goto Dianggap Berbahaya." Itu bukan masalah gaya: keluar dari lingkaran membuatnya sulit untuk secara formal beralasan tentang keadaan program. Saya telah menulis banyak
break;
pernyataan dalam hidup saya, dan sekali sebagai orang dewasa, saya bahkan menulis agoto
(untuk keluar dari berbagai tingkatan dalam lingkaran kinerja-kritis dan kemudian melanjutkan dengan cabang lain dari pohon pencarian). Namun, saya jauh lebih mungkin untuk menulisreturn
pernyataan kondisional dari loop (yang tidak pernah menjalankan kode setelah loop dan oleh karena itu tidak dapat membersihkan post-kondisi) daripada abreak
.Nota bene
Bahkan, refactoring kode untuk memberikan perilaku yang sama mungkin sebenarnya membutuhkan lebih banyak baris kode. Refactoring Anda dapat valid untuk beberapa kode lain tertentu atau jika kami dapat membuktikan bahwa kode tersebut
condition
akan mulai salah. Tetapi contoh Anda setara dalam kasus umum untuk:Jika beberapa kode lain bukan satu-liner, Anda mungkin kemudian memindahkannya ke suatu fungsi agar tidak mengulangi diri Anda sendiri, dan kemudian Anda hampir refactored loop Anda menjadi fungsi rekursif ekor.
Saya tahu ini bukan poin utama dari pertanyaan Anda, dan Anda menjaganya tetap sederhana.
sumber
break
pernyataan, maka Anda tahu apa kondisi loop dan bahwa loop berhenti ketika kondisi itu salah. Jika adabreak
? Lalu ada beberapa cara loop bisa berakhir, dan dalam kasus umum, mencari tahu kapan salah satu dari mereka bisa menghentikan loop secara harfiah memecahkan Masalah Berhenti. Dalam praktiknya, kekhawatiran saya yang lebih besar adalah bahwa loop itu terlihat seperti melakukan satu hal, tetapi sebenarnya, siapa pun yang menulis kode setelah loop mengabaikan kasus tepi yang terkubur dalam logika kompleksnya. Hal-hal dalam kondisi loop sulit untuk dilewatkan.Ya, tetapi sintaksis Anda tidak konvensional dan karenanya buruk (tm)
Semoga bahasa Anda mendukung sesuatu seperti
sumber
while
menekankan monster dalam kode - pengecualian yang tersembunyi di kode rutin / biasa. Logika bisnis ada di depan dan di tengah, mekanika perulangan dimasukkan. Ini menghindari "tunggu sebentar ..." reaksi terhadapfor
alternatif loop. Jawaban ini memperbaiki masalah. suara sepenuhnya.Jika Anda khawatir tentang
for
pernyataan yang terlalu rumit yang sulit dibaca, itu jelas merupakan keprihatinan yang valid. Membuang-buang ruang vertikal juga merupakan masalah (meskipun tidak terlalu kritis).(Secara pribadi saya tidak menyukai aturan bahwa
if
pernyataan harus selalu memiliki kawat gigi, yang sebagian besar merupakan penyebab ruang vertikal yang terbuang di sini. Perhatikan bahwa masalahnya adalah membuang - buang ruang vertikal. Menggunakan ruang vertikal dengan garis-garis yang berarti tidak boleh menjadi masalah.)Salah satu opsi adalah untuk membaginya menjadi beberapa baris. Ini jelas yang harus Anda lakukan jika Anda menggunakan
for
pernyataan yang sangat kompleks , dengan banyak variabel dan ketentuan. (Ini bagi saya penggunaan ruang vertikal yang lebih baik, memberikan sebanyak mungkin garis sesuatu yang bermakna.)Pendekatan yang lebih baik mungkin dengan mencoba menggunakan bentuk yang lebih deklaratif dan kurang imperatif. Ini akan bervariasi tergantung pada bahasanya, atau Anda mungkin perlu menulis fungsi Anda sendiri untuk mengaktifkan hal semacam ini. Itu juga tergantung apa yang
condition
sebenarnya. Agaknya itu harus dapat berubah entah bagaimana, tergantung pada apa yang ada dalam array.sumber
for
menjadi beberapa baris adalah ide terbaik dalam seluruh diskusi iniSatu hal yang dilupakan: Ketika saya putus dari satu loop (tidak melakukan semua iterasi yang mungkin, tidak peduli bagaimana diterapkan), itu biasanya terjadi bahwa saya tidak hanya ingin keluar dari loop, saya juga ingin tahu mengapa ini terjadi . Misalnya, jika saya mencari item X, saya tidak hanya berhenti dari loop, saya juga ingin tahu bahwa X ditemukan dan di mana itu.
Dalam situasi itu, memiliki kondisi di luar loop cukup alami. Jadi saya mulai dengan
dan dalam loop saya akan menulis
dengan for loop
Sekarang memeriksa kondisi dalam loop cukup alami. Apakah ada pernyataan "break" tergantung pada apakah ada proses lebih lanjut dalam loop yang ingin Anda hindari. Jika beberapa pemrosesan diperlukan dan pemrosesan lainnya tidak, Anda mungkin memiliki sesuatu seperti
suatu tempat di loop Anda.
sumber