2010-02-02 46 views
9

Công tắc có vẻ vô dụng vì chúng có thể được thay thế bằng câu lệnh if-else, có thể làm nhiều hơn là chỉ khớp với char/int/enum, v.v. diễn giải dòng lệnh args.Tại sao nên sử dụng bảng chuyển đổi thay vì nếu có các thống kê khác?

Một số cách sử dụng thực tế cho tuyên bố chuyển đổi là gì?

+3

Xem http://stackoverflow.com/questions/2103080/when-to-use-a-switch-statement-in-java, đặc trưng cho Java, nhưng nhiều nguyên tắc áp dụng ngôn ngữ-agnostically. –

+2

Chúng tôi đã lắp đặt đèn tín hiệu cho bạn để bạn có thể bật đèn và tắt đèn, không phải vì vậy bạn có thể ném những con sóng sáng! –

+1

http://stackoverflow.com/questions/449273/why-the-switch-statement-and-not-if-else-closed, http://stackoverflow.com/questions/97987/switch-vs-if-else , http://stackoverflow.com/questions/395618/if-else-vs-switch – Nope

Trả lời

25

Có hai lý do để sử dụng một switch vs if/else, trong tâm trí của tôi:

  • Trình biên dịch có thể tối ưu hóa cho việc chuyển đổi tốt hơn .
  • Tuyên bố chuyển đổi rõ ràng hơn thể hiện logic của mã tốt hơn.Cụ thể, ý tưởng rằng bạn đang dùng một nhánh khác tùy thuộc vào giá trị của một thứ gì đó, thay vì phụ thuộc vào logic phức tạp hơn. Đây là lý do quan trọng hơn đối với tôi.
+1

Tôi đã xem qua liên kết sau: http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx dường như hỗ trợ đối số tối ưu hóa của bạn (ít nhất là đối với .NET). Tôi đồng ý với điểm thứ hai của bạn là tốt. –

+0

+1 tối ưu hóa này đặc biệt quan trọng đối với mã nhúng đang xử lý thư theo kiểu gốc đệ quy. Tuy nhiên, một số trình biên dịch sẽ chỉ áp dụng tối ưu hóa bảng tra cứu nếu các giá trị số theo thứ tự hoặc độc lập với đơn đặt hàng. –

+0

Tôi cũng thích phần mở rộng của gcc: chuyển (foo) { trường hợp 1 ... 10: doSomething(); phá vỡ; trường hợp 11 ...200: doSomethingElse(); phá vỡ; } – ggiroux

9

Tôi sử dụng thiết bị chuyển mạch khi tôi đang sử dụng enum để quyết định những hành động mà phương pháp của tôi nên thực hiện. Nó giúp khi các hành động được loại trừ lẫn nhau.

4

Có một số trường hợp, một trong những điều chúng tôi phải giải quyết rất nhiều là nếu bạn có nhiều tùy chọn, cú pháp được nén nhiều hơn một chút và đôi khi dễ đọc hơn cú pháp if/then.

Mặc dù một đối số có thể được thực hiện để đi theo một trong hai cách, tôi thấy rằng các thiết bị chuyển mạch, trong trường hợp nhiều tùy chọn dễ đọc, duy trì và dễ hiểu hơn. Tôi cũng đã sử dụng nó trong một tình huống kiểu mẫu nhà máy, giúp tài liệu.

2

Đó là cách thích hợp để sử dụng ngôn ngữ. Nó cho phép trình biên dịch thực hiện một số tối ưu hóa và làm cho mã dễ đọc hơn bởi một người không phải là bạn.

Ngoài ra, trong một số ngôn ngữ, bạn có thể chuyển đổi enum và trình biên dịch sẽ cảnh báo nếu bạn bỏ lỡ các giá trị (tôi nghĩ).

2

bạn cũng có thể xóa các ngắt khỏi câu lệnh chuyển đổi. Bằng cách đó bạn có thể có điều này:

CASE_A:
...
BASE_B
...

do đó, cách mà bạn có thể có case_a kết hợp tất cả các trường hợp khác dưới nó cho đến khi nó chạm nghỉ ngơi . Không phải là tốt để làm điều đó chỉ với ifs.

+3

Điều này cũng rất dễ bị lỗi, khi ai đó đến và không nhận ra rằng đây là cách mã được dự định để hành xử. – danben

+0

Đôi khi nó hữu ích, trong trường hợp này nên là/* NHẬN XÉT ĐỂ CẦN THỰC HIỆN ĐỂ NHẬN THÔNG BÁO NHÂN DÂN THEO D BREAKI; * /. –

+2

Ngoài ra, một số ngôn ngữ (tôi nghĩ C#) buộc bạn phải khai báo một cách rõ ràng, hoặc trường hợp phải được để trống. –

18

Bạn cần phải nhớ rằng các nút chuyển dễ bảo trì hơn - một nhóm toàn bộ các ifs lồng nhau và elses có thể nhanh chóng trở thành nỗi đau để duy trì.

Công tắc cho phép lắp đặt dễ dàng vỏ mới.

+0

Đối với ifs lồng nhau, công tắc chắc chắn dễ bảo trì hơn. Đối với if/else-ifs (hoạt động giống như một switch) cũng dễ bảo trì như một công tắc –

7

Công tắc được tối ưu hóa bằng nhiều ngôn ngữ cho một số ngữ cảnh nhất định. Thường thì khi có thể, họ tạo ra một bảng nhảy hoặc thậm chí là bảng băm. Thực sự, khi đó là có thể để sử dụng nút chuyển, rất có khả năng sẽ hoạt động tốt hơn mã tương tự (logic) bằng cách sử dụng if/else.

1

Giúp dễ đọc - trong nháy mắt, tôi biết rằng quyết định cho khối mã nào sẽ chạy dựa trên các giá trị khác nhau của cùng một biến.

27

Có một vài trường hợp chuyển đổi dễ đọc hơn và có ích. Thông thường khi bạn có nhóm các tùy chọn.

Đây là một trong số họ:

int numDays = 0; 
    int month = 2; 
    int year = 2010; 

    // find the number of days in the month 
    switch (month) { 
     case 1: 
     case 3: 
     case 5: 
     case 7: 
     case 8: 
     case 10: 
     case 12: 
      numDays = 31; 
      break; 
     case 4: 
     case 6: 
     case 9: 
     case 11: 
      numDays = 30; 
      break; 
     case 2: 
      if (((year % 4 == 0) && !(year % 100 == 0)) 
       || (year % 400 == 0)) 
       numDays = 29; 
      else 
       numDays = 28; 
      break; 
     default: 
      System.out.println("Invalid month."); 
      break; 
    } 
+0

Yea, tôi đã tưởng tượng nó sẽ là trường hợp tương tự với các tùy chọn dòng lệnh. Giống như if -f tương tự như -F, người ta có thể sử dụng khái niệm đó. – defectivehalt

+0

@Kavon và đó là cách rất nhiều chương trình C xử lý các đối số chuyển đổi, sử dụng getopt() trong một khoảng thời gian() và chuyển() trên tên. –

4

Tôi luôn sử dụng các công tắc nếu tôi so sánh cùng một biến cho nhiều giá trị - chuyển đổi nhanh hơn rất nhiều mã (và dễ bảo trì hơn chuỗi dài nếu-elseif). Hãy tưởng tượng thay đổi tên biến, với một chuyển đổi nó sẽ là một chỉnh sửa duy nhất, với một chuỗi if-elseif nó sẽ là một số.

Ngoài ra, tùy thuộc vào ngôn ngữ bạn chọn, bạn có thể sử dụng trường hợp rơi qua "đối tượng địa lý" trong đó với chuỗi if-elseif bạn kết thúc bằng mã trùng lặp.

0

có thể dễ dàng hơn cho trình biên dịch để chuyển một câu lệnh chuyển đổi thành bảng công văn hơn là để biến súp tương đương nếu/khác thành bảng công văn. Nếu (và chỉ nếu) đó là sự thật, sau đó bạn sẽ có O (1) gửi đến mã có liên quan, thay vì O (log n) (hoặc O (n), nếu súp nếu/khác là xấu bằng văn bản).

Trong một số trường hợp (mặc dù không phải tất cả) nó cũng có thể dễ dàng hơn để kiểm tra xem bạn đã bao trả các bài kiểm tra cần thiết bằng cách sử dụng chuyển đổi hơn là một wodge nếu/else.

+0

Vấn đề là nếu súp khác chạy trong O (n) thì dễ hiểu hơn. –

+1

Không phải lúc nào. Nhìn vào ví dụ "ngày trong tháng", tôi thấy rằng có thể đọc được như một công trình if/else. Một nhược điểm nhỏ là những tháng có số ngày phổ biến ở một nơi, thay vì liệt kê mỗi tháng, tăng lên. Làm như vậy sẽ vẫn cho phép trình biên dịch sử dụng một bảng nhảy, mặc dù nó sẽ (có thể, tùy thuộc vào mức độ thông minh của trình biên dịch) gây ra kích thước mã lớn hơn. – Vatine

2

Một vài điểm:

  1. Một số ngôn ngữ cho phép bạn bật các loại giá trị khác, chẳng hạn như chuỗi (Coldfusion trường hợp tại điểm)
  2. Một câu lệnh switch có thể rất tốt được dễ dàng hơn nhiều mã để đọc hơn một khối lớn câu lệnh if/elseif/else
  3. Trong báo cáo chuyển đổi, bạn có thể ngắt ở cuối thùng hoặc cho phép mã tiếp tục xử lý các trường hợp khác trong tuyên bố. Chức năng này cho phép bạn dễ dàng lập mô hình một số quy tắc nếu các câu lệnh if/elseif/else không cho phép bạn thực hiện dễ dàng như vậy.
  4. Như những người khác đề cập, hãy nhớ rằng các trình biên dịch và động cơ có trình tối ưu hóa và các câu lệnh chuyển đổi được tối ưu hóa khác nhau.
2

Duff's Device. Tính hữu ích của nó trong thời hiện đại là gây tranh cãi, nhưng sự tuyệt vời của nó thì không.

+0

s/nó/của nó/g; (bỏ qua này parenthetical: chỉ padding ra bình luận đến 15 hoặc nhiều ký tự) – Anonymous

+0

doh! đã sửa. Tôi ghét nó khi người ta lạm dụng nó ... nó thường rất tốt về nó. Lấy làm tiếc. – rmeador

2

Trong trường hợp của Perl, sử dụng switch statement có thể làm giảm đáng kể độ phức tạp của mã của bạn.

Chỉ cần so sánh hai ví dụ sau.

  • Sử dụng given/when:

    use feature qw'switch'; 
    my $num_days; 
    given($month) { 
        when([ 1,3,5,7,8,10,12 ]){ $num_days = 31 } 
        when([ 4,6,9,11 ]){ $num_days = 30 } 
        when(2){ 
        $num_days = 29; 
        $num_days = 28 if  $year % 4; 
        $num_days = 28 unless $year % 100; 
        $num_days = 29 unless $year % 400; 
        default{ print "Invalid month.\n" } 
    } 
    
  • Sử dụng for như một sự thay thế cho các nhà điều hành mới ~~ (smart-match).

    my $num_days; 
    for(1,3,5,7,8,10,12){ 
        if($month == $_){ 
        $num_days = 31; 
        last; 
        } 
    } 
    for(4,6,9,11){ 
        if($month == $_){ 
        $num_days = 30; 
        last; 
        } 
    } 
    if($month == 2){ 
        $num_days = 29; 
        $num_days = 28 if  $year % 4; 
        $num_days = 28 unless $year % 100; 
        $num_days = 29 unless $year % 400; 
    } 
    unless(defined $num_days){ 
        print "Invalid month.\n" 
    } 
    
+3

Không phải ví dụ Perl nào cũng dễ đọc hơn. ;) – defectivehalt

0

tôi thích sử dụng một bản đồ để một công tắc trong hầu hết các trường hợp.

if (actionMap.contains(choice)) { 
    Action a = actionMap.get(choice); 
    a.execute(); 
} else { 
    //do something else 
} 

Nhưng trong trường hợp lựa chọn quá phức tạp để chuyển sang bản đồ hoặc khi nhiều hành động có thể được thực hiện chuyển đổi thì tốt hơn.

switch (choice) { 
    case 1: actionOne(); break; 
    case 2: if(actionOne()) {actionTwo()}; break; 
    case 3: if(!actionOne() && (actionTwo() > 1)) {actionThree()}; result = 7;break; 
    default: result = actionTwo(); 
} 

Đáng buồn thay, đôi khi yêu cầu phức tạp. Chuyển đổi rất hữu ích trong những trường hợp đó là phiên bản đơn giản của lồng nhau if/else constrcts.

2

Dường như với tôi rằng Ưu điểm chính của một công tắc là nó làm cho nó ngay lập tức rõ ràng để người đọc rằng tất cả các tùy chọn phụ thuộc vào các biến tương tự. Bạn chắc chắn có thể viết một khối if/elseif/elseif hoàn thành cùng một điều, nhưng sau đó người đọc sẽ phải kiểm tra cẩn thận rằng thực sự đó là biến tương tự đang được thử nghiệm mỗi lần.

Ngoài ra còn có kịch bản bảo trì cơn ác mộng nơi bạn có một ifif elseif dài trên cùng biến và ai đó quyết định thay đổi tên biến, và vì vậy anh ta thay đổi tất cả nếu ... ngoại trừ anh ta bỏ lỡ một.

Như những người khác đã chỉ ra, cũng có thực tế là trình biên dịch thường có thể tối ưu hóa nó tốt hơn.

0

Đừng hỏi lập trình viên python câu hỏi này vì ngôn ngữ không có tuyên bố chuyển đổi và khuyến khích sử dụng từ điển thay thế.

Để trả lời câu hỏi của bạn, tôi có thể nghĩ về một trường hợp trong đó câu lệnh chuyển đổi hữu ích. Nó rất hữu ích khi ngôn ngữ/trình biên dịch/phân tích tĩnh có thể đảm bảo rằng bạn đang kiểm tra tất cả các trường hợp. Điều này làm việc tốt với enums.

Nếu bạn thêm một mục khác vào một điều tra, bây giờ bạn có thể nhận được cảnh báo ở tất cả các nơi bạn đang thực hiện một chuyển đổi trên kiểu liệt kê đó cho bạn biết bạn đang thiếu một trường hợp.

+0

Tôi không nghĩ rằng đây là một lợi thế như là một khối 'else' cuối cùng ở cuối' if..else if ... '-chain đạt được điều tương tự ...' switch' không phải là 'enum '-thân thiện hơn' if'. – foraidt

Các vấn đề liên quan