Siapa yang memutuskan (dan berdasarkan konsep apa) yang harus digunakan switch
konstruksi (dalam banyak bahasa) break
di setiap pernyataan?
Mengapa kita harus menulis sesuatu seperti ini:
switch(a)
{
case 1:
result = 'one';
break;
case 2:
result = 'two';
break;
default:
result = 'not determined';
break;
}
(perhatikan ini di PHP dan JS; mungkin ada banyak bahasa lain yang menggunakan ini)
Jika switch
merupakan alternatif if
, mengapa kita tidak dapat menggunakan konstruksi yang sama seperti untuk if
? Yaitu:
switch(a)
{
case 1:
{
result = 'one';
}
case 2:
{
result = 'two';
}
default:
{
result = 'not determined';
}
}
Dikatakan bahwa break
mencegah eksekusi blok mengikuti yang sekarang. Tapi, apakah seseorang benar-benar mengalami situasi, di mana ada kebutuhan untuk eksekusi blok saat ini dan yang berikutnya? Saya tidak melakukannya. Bagi saya, break
selalu ada. Di setiap blok. Di setiap kode.
conditions
Trejder
sumber
sumber
CASE
pernyataan yang setara dengan raksasa jika / elseif diblokir.case 'a': case 'A': case 'b': case 'B'
tetapi sebagian besar karena saya tidak bisa melakukannyacase in [ 'a', 'A', 'b', 'B' ]
. Pertanyaan yang sedikit lebih baik adalah, dalam bahasa pilihan saya saat ini (C #), istirahat wajib , dan tidak ada fall-implisit; Lupabreak
adalah kesalahan sintaksis ...: \case TOKEN_A: /*set flag*/; case TOKEN_B: /*consume token*/; break; case TOKEN_C: /*...*/
break
ada di mana saja” adalah aturan yang jauh lebih sederhana untuk diterapkan daripada “Jangan memancarkan lompatan jikafallthrough
ada dalamswitch
”.Jawaban:
C adalah salah satu bahasa pertama yang memiliki
switch
pernyataan dalam bentuk ini, dan semua bahasa utama lainnya mewarisinya dari sana, sebagian besar memilih untuk mempertahankan semantik C per default - mereka juga tidak memikirkan keuntungan mengubahnya, atau menilai mereka kurang penting daripada menjaga perilaku semua orang dulu.Adapun mengapa C dirancang seperti itu, mungkin berasal dari konsep C sebagai "perakitan portabel". The
switch
pernyataan pada dasarnya adalah sebuah abstraksi dari meja cabang , dan meja cabang juga memiliki implisit jatuh-melalui dan membutuhkan instruksi jump tambahan untuk menghindarinya.Jadi pada dasarnya, para perancang C juga memilih untuk menjaga semantik assembler per default.
sumber
switchon
.when
.Karena
switch
bukan merupakan alternatifif ... else
pernyataan dalam bahasa-bahasa tersebut.Dengan menggunakan
switch
, kami dapat mencocokkan lebih dari satu kondisi pada satu waktu, yang sangat dihargai dalam beberapa kasus.Contoh:
sumber
more than one block ... unwanted in most cases
Saya tidak setuju dengan Anda.break
. Tapi ya, sejauh yang saya ketahui, Perangkat Duff tidak berfungsi di C #.C# does not support an implicit fall through from one case label to another
. Anda bisa jatuh, tetapi tidak ada kesempatan untuk secara tidak sengaja melupakan istirahat.if..else
tetapi dalam beberapa situasiswitch..case
akan lebih baik. Contoh di atas akan sedikit rumit jika kita menggunakan if-else.Ini telah ditanyakan pada Stack Overflow dalam konteks C: Mengapa pernyataan switch dirancang untuk membutuhkan istirahat?
Untuk meringkas jawaban yang diterima, itu mungkin sebuah kesalahan. Sebagian besar bahasa lain mungkin baru saja mengikuti C. Namun, beberapa bahasa seperti C # tampaknya telah memperbaikinya dengan membiarkan fall-through - tetapi hanya ketika programmer secara eksplisit mengatakannya (sumber: tautan di atas, saya tidak berbicara C # sendiri) .
sumber
/* FALLTHRU */
komentar dalam jawaban yang ditautkan oleh @Tapio di atas, untuk membuktikan bahwa Anda bersungguh-sungguh.goto case
, seperti tautannya, tidak menggambarkan mengapa itu bekerja dengan baik. Anda masih dapat menumpuk banyak kasus seperti di atas, tetapi segera setelah Anda memasukkan kode, Anda harus memiliki eksplisitgoto case whatever
untuk masuk ke kasus berikutnya atau Anda mendapatkan eror kompiler. Jika Anda bertanya kepada saya, dari keduanya, kemampuan untuk menumpuk kasus tanpa khawatir tentang kelalaian yang terjadi secara tidak sengaja adalah fitur yang jauh lebih baik daripada memungkinkan kegagalan secara eksplisitgoto case
.Saya akan menjawab dengan sebuah contoh. Jika Anda ingin membuat daftar jumlah hari untuk setiap bulan dalam setahun, jelas bahwa beberapa bulan memiliki 31, sekitar 30, dan 1 28/29. Akan terlihat seperti ini,
Ini adalah contoh di mana banyak kasus memiliki efek yang sama dan semuanya dikelompokkan bersama. Jelas ada alasan untuk pilihan kata kunci break dan bukan if ... else if construct.
Hal utama yang perlu diperhatikan di sini adalah bahwa pernyataan peralihan dengan banyak kasus serupa bukan jika ... atau jika ... lain jika ... lain untuk masing-masing kasus, melainkan jika (1, 2, 3) ... else if (4,5,6) else ...
sumber
if
tanpa manfaat apapun. Mungkin jika contoh Anda menetapkan nama atau apakah pekerjaan spesifik bulan sebagai tambahan dari fall-through, utilitas fall-through akan lebih jelas? (tanpa mengomentari apakah seseorang HARUS di tempat pertama)Ada dua situasi di mana "jatuh" dari satu kasus ke yang lain dapat terjadi - kasus kosong:
dan kasing kosong
Terlepas dari rujukan ke Perangkat Duff , contoh yang sah untuk kasus kedua sedikit dan jarang, dan umumnya dilarang dengan standar pengkodean dan ditandai selama analisis statis. Dan di mana ditemukan, itu lebih sering daripada tidak karena kelalaian a
break
.Yang pertama sangat masuk akal dan umum.
Sejujurnya, saya tidak dapat melihat alasan untuk membutuhkan
break
dan parser bahasa mengetahui bahwa tubuh kasus kosong sedang jatuh, sementara kasus tidak kosong adalah mandiri.Sangat disayangkan bahwa panel ISO C tampaknya lebih sibuk dengan menambahkan fitur-fitur baru (yang tidak diinginkan) ke bahasa, daripada memperbaiki fitur yang tidak ditentukan, tidak ditentukan atau implementasi-didefinisikan, belum lagi yang tidak logis.
sumber
Tidak memaksa
break
memungkinkan sejumlah hal yang sebaliknya bisa sulit dilakukan. Yang lain telah mencatat kasus pengelompokan, di mana ada sejumlah kasus yang tidak sepele.Satu kasus di mana sangat penting bahwa
break
tidak boleh digunakan adalah Perangkat Duff . Ini digunakan untuk " membuka gulungan " loop di mana ia dapat mempercepat operasi dengan membatasi jumlah perbandingan yang diperlukan. Saya percaya penggunaan awal memungkinkan fungsionalitas yang sebelumnya terlalu lambat dengan loop yang digulung penuh. Itu perdagangan ukuran kode untuk kecepatan dalam beberapa kasus.Merupakan praktik yang baik untuk mengganti
break
dengan komentar yang sesuai, jika kasing memiliki kode. Jika tidak, seseorang akan memperbaiki yang hilangbreak
, dan memperkenalkan bug.sumber
Di C, di mana asal tampaknya, blok kode
switch
pernyataan itu bukan konstruksi khusus. Ini adalah blok kode yang normal, seperti halnya blok di bawahif
pernyataan.case
dandefault
melompati label di dalam blok ini, khususnya terkait denganswitch
. Mereka ditangani sama seperti label lompat biasagoto
. Ada satu aturan khusus yang penting di sini: Label lompat dapat hampir di mana-mana dalam kode, tanpa mengganggu aliran kode.Sebagai blok kode normal, itu tidak harus berupa pernyataan majemuk. Label juga opsional. Ini adalah
switch
pernyataan yang valid dalam C:Standar C sendiri memberikan ini sebagai contoh (6.8.4.2):
Selain itu,
default
label lompat juga, dan dengan demikian bisa di mana saja, tanpa perlu menjadi kasus terakhir.Ini juga menjelaskan Perangkat Duff:
Mengapa jatuh? Karena dalam aliran kode normal dalam blok kode normal , diharapkan untuk menjalankan pernyataan berikutnya , seperti yang Anda harapkan dalam
if
blok kode.Dugaan saya adalah bahwa alasan untuk ini adalah kemudahan implementasi. Anda tidak perlu kode khusus untuk
switch
mem -parsing dan menyusun blok, merawat aturan khusus. Anda cukup menguraikannya seperti kode lain dan hanya perlu merawat label dan pemilihan lompat.Pertanyaan tindak lanjut yang menarik dari semua ini adalah apakah pernyataan bersarang berikut mencetak "Selesai." atau tidak.
Standar C memperhatikan hal ini (6.8.4.2.4):
sumber
Beberapa orang telah menyebutkan gagasan mencocokkan berbagai kondisi, yang sangat berharga dari waktu ke waktu. Namun kemampuan untuk mencocokkan beberapa kondisi tidak selalu mengharuskan Anda melakukan hal yang sama persis dengan setiap kondisi yang cocok. Pertimbangkan yang berikut ini:
Ada dua cara yang berbeda set beberapa kondisi dicocokkan di sini. Dengan kondisi 1 dan 2, mereka hanya jatuh ke plot kode yang sama persis dan melakukan hal yang sama persis. Namun dengan kondisi 3 dan 4, meskipun keduanya berakhir dengan panggilan
doSomething3And4()
, hanya 3 panggilandoSomething3()
.sumber
case 2
memicu, jadi jika kita ingin menjadi benar (dan kita lakukan) yang asli nama fungsi harus berupadoSomethingBecause_1_OR_2_OR_1AND2()
atau sesuatu (walaupun kode yang sah di mana sebuah immutable cocok dengan dua kasus yang berbeda saat masih menjadi kode yang ditulis dengan baik hampir tidak ada, jadi setidaknya ini seharusnyadoSomethingBecause1or2()
)doSomething[ThatShouldBeDoneInTheCaseOf]1And[InTheCaseOf]2()
,. Itu tidak mengacu pada logis dan / atau.Untuk menjawab dua pertanyaan Anda.
Mengapa C perlu istirahat?
Ia datang ke akar Cs sebagai "assembler portabel". Di mana kode psudo seperti ini umum: -
pernyataan sakelar dirancang untuk menyediakan fungsionalitas serupa di tingkat yang lebih tinggi.
Apakah kita pernah memiliki sakelar tanpa putus?
Ya ini sangat umum dan ada beberapa kasus penggunaan;
Pertama, Anda mungkin ingin mengambil tindakan yang sama untuk beberapa kasus. Kami melakukan ini dengan menumpuk kasus di atas satu sama lain:
Kasus penggunaan lain yang umum di mesin negara adalah bahwa setelah memproses satu negara kami segera ingin masuk dan memproses negara lain:
sumber
Pernyataan break adalah pernyataan melompat yang memungkinkan pengguna untuk keluar dari saklar penutup terdekat (untuk kasus Anda), sementara, lakukan, untuk atau foreach. itu semudah itu.
sumber
Saya pikir dengan semua yang tertulis di atas - hasil utama utas ini adalah bahwa jika Anda ingin merancang bahasa baru - defaultnya adalah Anda tidak perlu menambahkan
break
pernyataan dan kompiler akan memperlakukannya seperti jika Anda melakukannya.Jika Anda ingin kasus langka di mana Anda ingin melanjutkan ke kasus berikutnya - cukup nyatakan dengan
continue
pernyataan.Ini dapat ditingkatkan sehingga hanya jika Anda menggunakan kurung keriting di dalam case maka itu tidak berjalan sehingga contoh dengan bulan-bulan di atas dari beberapa kasus melakukan kode persis sama - akan selalu bekerja seperti yang diharapkan tanpa memerlukan
continue
.sumber
*
,&
,static
dll