Saya menemukan pertanyaan ini beberapa detik yang lalu, dan saya menarik beberapa materi dari sana: Apakah ada nama untuk konstruksi 'break n'?
Ini tampaknya menjadi cara rumit yang tidak perlu bagi orang-orang untuk menginstruksikan program untuk keluar dari double-nested for loop:
for (i = 0; i < 10; i++) {
bool broken = false;
for (j = 10; j > 0; j--) {
if (j == i) {
broken = true;
break;
}
}
if (broken)
break;
}
Saya tahu buku-buku teks suka mengatakan pernyataan goto adalah iblis, dan saya sendiri tidak suka sama sekali, tetapi apakah ini membenarkan pengecualian terhadap aturan tersebut?
Saya mencari jawaban yang berhubungan dengan n-nested for loop.
CATATAN: Apakah Anda menjawab ya, tidak, atau di suatu tempat di antara, jawaban yang benar-benar tertutup tidak diterima. Terutama jika jawabannya tidak, maka berikan alasan yang baik dan sah mengapa (yang tidak terlalu jauh dari peraturan Stack Exchange).
sumber
for (j = 10; j > 0 && !broken; j--)
maka Anda tidak perlubreak;
pernyataan itu. Jika Anda memindahkan deklarasibroken
ke sebelum loop luar dimulai, maka jika itu bisa ditulisfor (i = 0; i < 10 && !broken; i++)
maka saya pikir tidak adabreak;
yang diperlukan.goto
: goto (C # Reference) - "Pernyataan goto juga berguna untuk keluar dari loop yang bersarang."goto
sebenarnya diperlukan dalam saklar C # untuk beralih ke kasus lain setelah mengeksekusi kode apa pun di dalam kasus pertama. Itu adalah satu-satunya kasus saya menggunakan goto.Jawaban:
Kebutuhan nyata untuk pernyataan masuk muncul dari Anda memilih ekspresi kondisional yang buruk untuk loop .
Anda menyatakan bahwa Anda ingin lingkaran luar terus berlanjut selama
i < 10
dan yang terdalam terus berlanjut selamaj > 0
.Tetapi pada kenyataannya bukan itu yang Anda inginkan , Anda tidak memberi tahu loop kondisi sebenarnya yang Anda ingin mereka evaluasi, maka Anda ingin menyelesaikannya dengan menggunakan break atau goto.
Jika Anda memberi tahu loop niat sebenarnya Anda untuk memulai , maka tidak perlu istirahat atau kebagian.
sumber
i
di akhir loop luar, jadi penambahan arus pendek penting untuk membuat kode terlihat 100% setara. Saya tidak mengatakan apa-apa dalam jawaban Anda salah, saya hanya ingin menunjukkan bahwa melanggar loop segera adalah merupakan aspek penting dari kode.i
di akhir loop luar dalam pertanyaan OP.goto
(saya yakin ada yang lebih baik), bahkan jika itu memunculkan pertanyaan yang tampaknya menggunakannya seperti itu, tetapi untuk menggambarkan tindakan dasarbreak(n)
dalam bahasa yang tidak t mendukungnya.Dalam hal ini, Anda bisa mengubah kode menjadi rutin yang terpisah, dan kemudian hanya
return
dari loop dalam. Itu akan meniadakan kebutuhan untuk keluar dari lingkaran luar:sumber
i
setelah akhir lingkaran luar. Jadi untuk benar-benar mencerminkan itui
adalah nilai penting, di sinireturn true;
danreturn false;
harus sama-samareturn i;
.Tidak, saya pikir tidak
goto
perlu. Jika Anda menulisnya seperti ini:Memiliki
&&!broken
pada kedua loop memungkinkan Anda keluar dari kedua loop ketikai==j
.Bagi saya, pendekatan ini lebih disukai. Kondisi lingkaran sangat jelas:
i<10 && !broken
.Versi yang berfungsi dapat dilihat di sini: http://rextester.com/KFMH48414
Kode:
Keluaran:
sumber
broken
dalam contoh pertama Anda sama sekali ? Cukup gunakan break pada loop dalam. Juga, jika Anda benar-benar harus menggunakanbroken
, mengapa menyatakannya di luar loop? Nyatakan saja di dalami
loop. Adapunwhile
loop, tolong jangan gunakan itu. Jujur saya pikir itu berhasil menjadi lebih mudah dibaca daripada versi goto.broken
digunakan karena saya tidak suka menggunakanbreak
pernyataan (kecuali dalam switch-case, tapi hanya itu). Ini dinyatakan di luar loop luar jika Anda ingin memutuskan SEMUA loop ketikai==j
. Anda benar, secara umum,broken
hanya perlu dinyatakan sebelum loop terluar bahwa itu akan rusak.i==2
di akhir loop. Kondisi keberhasilan juga harus memotong arus kenaikan jika harus 100% setara dengan abreak 2
.broken = (j == i)
suka daripada jika dan, jika bahasa memungkinkan, menempatkan deklarasi yang rusak di dalam inisialisasi loop luar. Meskipun sulit untuk mengatakan hal-hal ini untuk contoh khusus ini, karena seluruh loop adalah no-op (tidak mengembalikan apa-apa dan tidak memiliki efek samping) dan jika itu melakukan sesuatu, itu mungkin melakukan itu di dalam if (walaupun saya masihbroken = (j ==i); if broken { something(); }
lebih suka pribadi)i
setelah akhir lingkaran luar. Dengan kata lain, satu-satunya pemikiran yang sangat penting adalah kapan tepatnya ia keluar dari lingkaran luar.Jawaban singkatnya adalah "itu tergantung". Saya menganjurkan untuk memilih tentang keterbacaan dan pemahaman kode Anda. Cara goto mungkin lebih mudah dibaca daripada mengutak-atik kondisi, atau sebaliknya. Anda juga dapat mempertimbangkan prinsip kejutan terkecil, pedoman yang digunakan di toko / proyek dan konsistensi basis kode. Sebagai contoh, goto untuk meninggalkan switch atau untuk penanganan kesalahan adalah praktik umum dalam basis kode kernel Linux. Perhatikan juga bahwa beberapa programmer mungkin mengalami masalah dalam membaca kode Anda (baik dibesarkan dengan mantra "keburukan jahat", atau hanya tidak dipelajari karena guru mereka berpikir demikian) dan beberapa dari mereka bahkan mungkin "menghakimi Anda".
Secara umum, goto yang bergerak lebih jauh dalam fungsi yang sama sering diterima, terutama jika lompatannya tidak terlalu lama. Kasus penggunaan Anda untuk meninggalkan nested loop adalah salah satu contoh goto yang "tidak terlalu jahat".
sumber
Dalam kasus Anda, goto sudah cukup untuk perbaikan sehingga terlihat menggoda, tetapi itu bukan perbaikan yang layak melanggar aturan untuk tidak menggunakannya dalam basis kode Anda.
Pikirkan pengulas masa depan Anda: ia harus berpikir, "Apakah orang ini pembuat kode yang buruk atau apakah ini sebenarnya merupakan kasus di mana goto itu sepadan? Biarkan saya mengambil 5 menit untuk memutuskan ini untuk diri saya sendiri atau penelitian pada Internet." Mengapa Anda melakukan itu pada pembuat kode masa depan Anda ketika Anda tidak dapat menggunakan sepenuhnya goto?
Secara umum mentalitas ini berlaku untuk semua kode "buruk" dan bahkan mendefinisikannya: jika berfungsi sekarang, dan bagus dalam hal ini, tetapi menciptakan upaya untuk memverifikasi itu benar, yang di era ini goto akan selalu dilakukan, maka jangan lakukan.
Yang sedang berkata, ya, Anda menghasilkan salah satu kasus yang sedikit lebih sulit. Kamu boleh:
Sangat sulit bagi saya untuk membuat kasus di mana loop ganda tidak begitu kohesif sehingga seharusnya tidak menjadi rutinitas sendiri.
Ngomong-ngomong, diskusi terbaik tentang ini yang pernah saya lihat adalah Kode Lengkap Steve McConnell . Jika Anda senang memikirkan masalah-masalah ini secara kritis, saya sangat merekomendasikan membaca, bahkan secara langsung meskipun sangat luas.
sumber
TLD; DR: Tidak secara spesifik, ya secara umum
Untuk contoh spesifik yang Anda gunakan, saya akan mengatakan tidak karena alasan yang sama seperti yang ditunjukkan oleh banyak orang lain. Anda dapat dengan mudah memperbaiki kode menjadi bentuk yang setara baik yang menghilangkan kebutuhan untuk
goto
.Secara umum pelarangan terhadap
goto
adalah generalisasi berdasarkan sifat yang dipahamigoto
dan biaya menggunakannya. Bagian dari rekayasa perangkat lunak adalah membuat keputusan implementasi. Justifikasi dari keputusan-keputusan itu terjadi dengan menimbang biaya terhadap manfaat dan kapan pun manfaatnya melebihi biaya pelaksanaannya dibenarkan. Kontroversi muncul karena penilaian yang berbeda, baik biaya maupun manfaatnya.Intinya adalah akan selalu ada pengecualian di mana a
goto
dibenarkan, tetapi hanya untuk beberapa karena penilaian yang berbeda. Sayang sekali banyak insinyur hanya mengecualikan teknik dalam ketidaktahuan sengaja karena mereka membacanya di internet daripada meluangkan waktu untuk memahami mengapa.sumber
Saya rasa kasus ini tidak membenarkan pengecualian, karena ini dapat ditulis sebagai:
sumber