Ganti pernyataan dengan pengembalian - kebenaran kode


91

Katakanlah saya memiliki kode dalam C dengan kira-kira struktur ini:

switch (something)
{
    case 0:
      return "blah";
      break;

    case 1:
    case 4:
      return "foo";
      break;

    case 2:
    case 3:
      return "bar";
      break;

    default:
      return "foobar";
      break;
}

Sekarang jelas, breaks tidak diperlukan agar kode dapat berjalan dengan benar, tetapi sepertinya praktik yang buruk jika saya tidak meletakkannya di sana kepada saya.

Bagaimana menurut anda? Apakah boleh menghapusnya? Atau apakah Anda akan menyimpannya untuk meningkatkan "kebenaran"?

Jawaban:


139

Hapus breakpernyataan tersebut. Mereka tidak diperlukan dan mungkin beberapa kompiler akan mengeluarkan peringatan "Kode tidak dapat dijangkau" .


2
Hal yang sama berlaku dengan pernyataan lompat kontrol tanpa syarat lainnya, seperti continueatau goto- itu idiomatis untuk menggunakannya sebagai pengganti break.
caf

32

Saya akan mengambil taktik yang berbeda sepenuhnya. Jangan KEMBALI di tengah metode / fungsi. Sebagai gantinya, masukkan saja nilai pengembalian dalam variabel lokal dan kirimkan di akhir.

Secara pribadi, menurut saya yang berikut ini lebih mudah dibaca:

String result = "";

switch (something) {
case 0:
  result = "blah";
  break;
case 1:
  result = "foo";
  break;
}

return result;

24
Filosofi "One Exit" masuk akal di C, di mana Anda perlu memastikan segala sesuatunya dibersihkan dengan benar. Mempertimbangkan di C ++ Anda dapat ditarik keluar dari fungsi pada titik mana pun dengan pengecualian, filosofi satu keluar tidak terlalu berguna di C ++.
Billy ONeal

29
Secara teori, ini adalah ide bagus, tetapi sering kali memerlukan blok kontrol ekstra yang dapat menghambat keterbacaan.
mikerobi

8
Alasan utama mengapa saya melakukan hal-hal seperti ini, adalah bahwa dalam fungsi yang lebih panjang, sangat mudah untuk melewatkan vektor keluar saat memindai melalui kode. Namun, ketika jalan keluar selalu berada di ujung, maka lebih mudah untuk dengan cepat memahami apa yang sedang terjadi.
NotMe

7
Nah, itu, dan mengembalikan blok di tengah kode hanya mengingatkan saya pada penyalahgunaan GOTO.
NotMe

5
@ Chris: Dalam fungsi yang lebih panjang, saya sangat setuju - tetapi itu biasanya menunjukkan masalah yang lebih besar, jadi perbaiki ulang. Dalam banyak kasus, ini adalah fungsi sepele yang kembali saat sakelar, dan sangat jelas apa yang seharusnya terjadi, jadi jangan sia-siakan kekuatan otak untuk melacak variabel tambahan.
Stephen

8

Secara pribadi saya akan menghapus pengembalian dan mempertahankan istirahat. Saya akan menggunakan pernyataan switch untuk menetapkan nilai ke variabel. Kemudian kembalikan variabel itu setelah pernyataan switch.

Meskipun ini adalah poin yang bisa diperdebatkan, saya selalu merasa bahwa desain dan enkapsulasi yang baik berarti satu jalan masuk dan satu jalan keluar. Jauh lebih mudah untuk menjamin logika dan Anda tidak akan melewatkan kode pembersihan secara tidak sengaja berdasarkan kompleksitas siklus fungsi Anda.

Satu pengecualian: Mengembalikan lebih awal tidak masalah jika parameter buruk terdeteksi di awal fungsi - sebelum resource apa pun diperoleh.


Mungkin bagus untuk yang ini switch, tapi belum tentu yang terbaik secara umum. Nah, katakanlah pernyataan switch di dalam suatu fungsi mendahului 500 baris kode lain yang berlaku hanya ketika kasus-kasus tertentu true. Apa gunanya menjalankan semua kode ekstra itu untuk kasus-kasus yang tidak perlu mengeksekusinya; bukankah lebih baik hanya returndi dalam switchuntuk caseitu?
Fr0zenFyr

6

Pertahankan jeda - Anda cenderung tidak mengalami masalah jika / ketika Anda mengedit kode nanti jika jeda sudah ada.

Karena itu, dianggap oleh banyak orang (termasuk saya) sebagai praktik buruk untuk kembali dari tengah suatu fungsi. Idealnya sebuah fungsi harus memiliki satu titik masuk dan satu titik keluar.


5

Hapus mereka. Ini idiomatis untuk kembali dari casepernyataan, dan sebaliknya itu adalah "kode tidak terjangkau".


5

Saya akan menghapusnya. Dalam buku saya, kode mati seperti itu harus dianggap kesalahan karena membuat Anda melakukan pengambilan ganda dan bertanya pada diri sendiri "Bagaimana saya bisa mengeksekusi baris itu?"


4

Saya biasanya menulis kode tanpa mereka. IMO, kode mati cenderung menunjukkan kecerobohan dan / atau kurangnya pemahaman.

Tentu saja, saya juga akan mempertimbangkan sesuatu seperti:

char const *rets[] = {"blah", "foo", "bar"};

return rets[something];

Sunting: bahkan dengan kiriman yang telah diedit, gagasan umum ini dapat bekerja dengan baik:

char const *rets[] = { "blah", "foo", "bar", "bar", "foo"};

if ((unsigned)something < 5)
    return rets[something]
return "foobar";

Di beberapa titik, terutama jika nilai inputnya jarang (mis., 1, 100, 1000, dan 10000), Anda menginginkan array yang jarang. Anda dapat mengimplementasikannya sebagai pohon atau peta dengan cukup baik (meskipun, tentu saja, sakelar masih berfungsi dalam kasus ini juga).


Mengedit postingan untuk mencerminkan mengapa solusi ini tidak berfungsi dengan baik.
houbysoft

@ edit Anda: Ya, tetapi akan membutuhkan lebih banyak memori, dll. IMHO sakelar adalah cara termudah, yang saya inginkan dalam fungsi sekecil itu (hanya sakelar).
houbysoft

3
@houbysoft: perhatikan baik-baik sebelum Anda menyimpulkan bahwa itu akan membutuhkan memori ekstra. Dengan kompiler biasa, menggunakan "foo" dua kali (misalnya) akan menggunakan dua pointer ke satu blok data, tidak mereplikasi data. Anda juga bisa mengharapkan kode yang lebih pendek. Kecuali Anda memiliki banyak nilai berulang, ini akan sering menghemat memori secara keseluruhan.
Jerry Coffin

benar. Saya akan tetap berpegang pada solusi saya karena daftar nilai sangat panjang, dan peralihan sepertinya lebih baik.
houbysoft

1
Memang, jawaban yang lebih elegan dan efisien untuk masalah seperti ini, ketika nilai sakelar bersebelahan dan tipe datanya homogen, adalah dengan menggunakan larik, hindari sakelar sama sekali.
Dwayne Robinson

2

Saya akan mengatakan hapus mereka dan tentukan default: branch.


Jika tidak ada default yang masuk akal maka Anda tidak harus menentukan default.
Billy ONeal

ada satu, dan saya tentukan satu, saya hanya tidak memasukkannya ke dalam pertanyaan, mengeditnya sekarang.
houbysoft

2

Bukankah lebih baik memiliki array dengan

arr[0] = "blah"
arr[1] = "foo"
arr[2] = "bar"

dan lakukan return arr[something];?

Jika ini tentang praktik secara umum, Anda harus tetap breakmengalihkan pernyataan. Jika Anda tidak membutuhkan returnpernyataan di masa mendatang, hal itu mengurangi kemungkinan pernyataan tersebut gagal ke pernyataan berikutnya case.


Mengedit postingan untuk mencerminkan mengapa solusi ini tidak berfungsi dengan baik.
houbysoft

2

Untuk "kebenaran", entri tunggal, blok keluar tunggal adalah ide yang bagus. Setidaknya itulah saat saya mengambil gelar ilmu komputer. Jadi saya mungkin akan mendeklarasikan variabel, menetapkannya di sakelar dan mengembalikannya sekali di akhir fungsi


2

Bagaimana menurut anda? Apakah boleh menghapusnya? Atau apakah Anda akan menyimpannya untuk meningkatkan "kebenaran"?

Tidak masalah untuk menghapusnya. Menggunakan return adalah persis skenario di mana breaktidak boleh digunakan.


1

Menarik. Konsensus dari sebagian besar jawaban ini tampaknya adalah bahwa breakpernyataan yang berlebihan adalah kekacauan yang tidak perlu. Di sisi lain, saya membaca breakpernyataan di sakelar sebagai 'penutupan' dari sebuah kasus. caseblok yang tidak berakhir dengan breakcenderung melompat ke arah saya sebagai potensi jatuh melalui bug.

Saya tahu bahwa bukan itu yang terjadi ketika ada returnalih - alih a break, tetapi begitulah cara mata saya 'membaca' blok kasing di sakelar, jadi saya pribadi lebih suka masing-masing casedipasangkan dengan a break. Tetapi banyak penyusun yang mengeluh tentang breaksetelah returnmenjadi berlebihan / tidak dapat dijangkau, dan tampaknya saya tampaknya termasuk minoritas.

Jadi singkirkan yang breakberikut ini a return.

NB: semua ini mengabaikan apakah melanggar aturan single entry / exit adalah ide yang bagus atau tidak. Sejauh itu, saya berpendapat bahwa sayangnya berubah tergantung pada keadaan ...


0

Saya katakan hapus mereka. Jika kode Anda sangat tidak terbaca sehingga Anda perlu memasukkan jeda di sana 'agar aman', Anda harus mempertimbangkan kembali gaya pengkodean Anda :)

Juga saya selalu memilih untuk tidak mencampur istirahat dan pengembalian dalam pernyataan saklar, melainkan tetap dengan salah satunya.


0

Saya pribadi cenderung kehilangan breaks. Mungkin salah satu sumber kebiasaan ini adalah dari prosedur jendela pemrograman untuk aplikasi Windows:

LRESULT WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_SIZE:
            return sizeHandler (...);
        case WM_DESTROY:
            return destroyHandler (...);
        ...
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Saya pribadi menemukan pendekatan ini jauh lebih sederhana, ringkas dan fleksibel daripada mendeklarasikan variabel pengembalian yang ditetapkan oleh masing-masing penangan, kemudian mengembalikannya di akhir. Dengan pendekatan ini, breaks adalah redundan dan oleh karena itu harus pergi - mereka tidak melayani tujuan yang berguna (secara sintaksis atau IMO secara visual) dan hanya membengkak kode.


0

Saya pikir * break * s ada untuk suatu tujuan. Itu untuk menjaga 'ideologi' pemrograman tetap hidup. Jika kita hanya 'memprogram' kode kita tanpa koherensi logis mungkin itu bisa dibaca oleh Anda sekarang, tapi coba besok. Cobalah menjelaskannya kepada atasan Anda. Coba jalankan di Windows 3030.

Bleah, idenya sangat sederhana:


Switch ( Algorithm )
{

 case 1:
 {
   Call_911;
   Jump;
 }**break**;
 case 2:
 {
   Call Samantha_28;
   Forget;
 }**break**;
 case 3:
 {
   Call it_a_day;
 }**break**;

Return thinkAboutIt?1:return 0;

void Samantha_28(int oBed)
{
   LONG way_from_right;
   SHORT Forget_is_my_job;
   LONG JMP_is_for_assembly;
   LONG assembly_I_work_for_cops;

   BOOL allOfTheAbove;

   int Elligence_says_anyways_thinkAboutIt_**break**_if_we_code_like_this_we_d_be_monkeys;

}
// Sometimes Programming is supposed to convey the meaning and the essence of the task at hand. It is // there to serve a purpose and to keep it alive. While you are not looking, your program is doing  // its thing. Do you trust it?
// This is how you can...
// ----------
// **Break**; Please, take a **Break**;

/ * Hanya pertanyaan kecil sekalipun. Berapa banyak kopi yang Anda miliki saat membaca penjelasan di atas? TI Terkadang merusak sistem * /


0

Keluar dari kode pada satu titik. Itu memberikan keterbacaan kode yang lebih baik. Menambahkan pernyataan kembali (Beberapa keluar) di antaranya akan membuat proses debug menjadi sulit.


0

Jika Anda memiliki jenis kode "pencarian", Anda dapat mengemas klausa switch-case dalam sebuah metode dengan sendirinya.

Saya memiliki beberapa di antaranya dalam sistem "hobi" yang saya kembangkan untuk bersenang-senang:

private int basePerCapitaIncomeRaw(int tl) {
    switch (tl) {
        case 0:     return 7500;
        case 1:     return 7800;
        case 2:     return 8100;
        case 3:     return 8400;
        case 4:     return 9600;
        case 5:     return 13000;
        case 6:     return 19000;
        case 7:     return 25000;
        case 8:     return 31000;
        case 9:     return 43000;
        case 10:    return 67000;
        case 11:    return 97000;
        default:    return 130000;
    }
}

(Ya. Itu ruang GURPS ...)

Saya setuju dengan orang lain bahwa Anda dalam banyak kasus harus menghindari lebih dari satu pengembalian dalam suatu metode, dan saya menyadari bahwa yang ini mungkin lebih baik diimplementasikan sebagai larik atau yang lain. Saya baru saja menemukan switch-case-return menjadi pertandingan yang cukup mudah untuk tabel pencarian dengan korelasi 1-1 antara input dan output, seperti hal di atas (permainan role-playing penuh dengan mereka, saya yakin mereka ada di "bisnis" juga): D

Di sisi lain, jika case-clause lebih kompleks, atau sesuatu terjadi setelah switch-statement, saya tidak akan merekomendasikan menggunakan return di dalamnya, melainkan menetapkan variabel di switch, mengakhirinya dengan jeda, dan mengembalikan nilai variabel pada akhirnya.

(Di sisi ... ketiga? Sisi ... Anda selalu dapat merefaktor sebuah saklar ke dalam metodenya sendiri ... Saya ragu ini akan berpengaruh pada kinerja, dan tidak akan mengejutkan saya jika kompiler modern bahkan dapat mengenalinya sebagai sesuatu yang bisa disisipkan ...)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.