Các câu lệnh chuyển đổi luôn chứa một mệnh đề mặc định?


255

Trong một trong những đánh giá mã đầu tiên của tôi (một thời gian trước), tôi được cho biết rằng nên bao gồm một mệnh đề mặc định trong tất cả các câu lệnh chuyển đổi. Gần đây tôi đã nhớ lời khuyên này nhưng không thể nhớ những gì biện minh. Nghe có vẻ khá kỳ lạ với tôi bây giờ.

  1. Có một lý do hợp lý cho việc luôn luôn bao gồm một tuyên bố mặc định?

  2. Là ngôn ngữ này phụ thuộc? Tôi không nhớ ngôn ngữ nào tôi đang sử dụng vào thời điểm đó - có thể ngôn ngữ này áp dụng cho một số ngôn ngữ và không áp dụng cho ngôn ngữ khác?


9
Nó sẽ phụ thuộc vào ngôn ngữ ở một mức độ lớn
skaffman

Câu trả lời:


277

Trường hợp chuyển đổi hầu như luôn luôn có một defaulttrường hợp.

Lý do nên sử dụng default

1.Để 'bắt' một giá trị bất ngờ

switch(type)
{
    case 1:
        //something
    case 2:
        //something else
    default:
        // unknown type! based on the language,
        // there should probably be some error-handling
        // here, maybe an exception
}

2. Để xử lý các hành động 'mặc định', trong đó các trường hợp dành cho hành vi đặc biệt.

Bạn thấy điều này rất nhiều trong các chương trình điều khiển menu và các tập lệnh bash shell. Bạn cũng có thể thấy điều này khi một biến được khai báo bên ngoài trường hợp chuyển đổi nhưng không được khởi tạo và mỗi trường hợp khởi tạo nó thành một thứ khác. Ở đây, mặc định cũng cần phải khởi tạo nó để mã dòng truy cập vào biến không gây ra lỗi.

3. Để cho ai đó đọc mã của bạn rằng bạn đã bao gồm trường hợp đó.

variable = (variable == "value") ? 1 : 2;
switch(variable)
{
    case 1:
        // something
    case 2:
        // something else
    default:
        // will NOT execute because of the line preceding the switch.
}

Đây là một ví dụ đơn giản hóa quá mức, nhưng vấn đề là ai đó đang đọc mã không nên tự hỏi tại sao variablekhông thể là thứ gì đó ngoài 1 hoặc 2.


Trường hợp duy nhất tôi có thể nghĩ đến KHÔNG sử dụng defaultkhi công tắc đang kiểm tra thứ gì đó trong đó rõ ràng là mọi sự thay thế khác có thể được bỏ qua một cách vui vẻ

switch(keystroke)
{
    case 'w':
        // move up
    case 'a':
        // move left
    case 's':
        // move down
    case 'd':
        // move right
    // no default really required here
}

25
Ví dụ của bạn về loại tổ hợp phím trái ngược với phần còn lại của những gì bạn vừa nói. : | Tôi nghĩ rằng một lời giải thích nhiều hơn sẽ có ý nghĩa như: bạn không quan tâm đến một mặc định trong trường hợp này bởi vì nếu nhấn một phím khác, bạn không quan tâm, nhưng nếu một biến được truyền vào khác với dự kiến, chúng tôi quan tâm .
Andrew

1
Đồng thời nếu bạn đang kiểm tra tham số GET, bạn có thể không muốn ném ngoại lệ mỗi khi người dùng thay đổi url nhận thành thứ gì đó không hợp lệ: [
Andrew

4
@Andrew WASD là phổ biến cho các chuyển động của nhân vật trong máy tính. Bạn sẽ không cần bất kỳ hành động mặc định nào vì các phím khác có thể được gán cho các tương tác khác. Trong loại chuyển đổi này, thật tốt để gọi các chức năng chuyển động.
jemiloii 17/2/2016

13
Một số trình biên dịch cảnh báo khi bật enum nếu trường hợp bị bỏ sót và thêm trường hợp mặc định sẽ chặn cảnh báo đó. Cho rằng đây là kinh nghiệm của tôi, một lỗi rất phổ biến (quên cập nhật công tắc ở đâu đó sau khi thêm giá trị enum), đây có vẻ là một lý do rất chính đáng để bỏ qua trường hợp mặc định.
rdb

3
@virusrocks Nếu tình trạng của bạn là enum, bạn vẫn có thể có các giá trị không mong muốn. Ví dụ: nếu bạn thêm một giá trị mới vào enum và quên cập nhật một công tắc. Ngoài ra, trong một số ngôn ngữ, bạn có thể gán giá trị nguyên cho enums. Trong C ++, enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;tạo một thể hiện hợp lệ MyEnumkhông bằng FOOhoặc BAR. Nếu một trong những vấn đề này sẽ gây ra lỗi trong dự án của bạn, một trường hợp mặc định sẽ giúp bạn tìm ra lỗi rất nhanh, thường không cần trình gỡ lỗi!
cdgraham

54

Không.

Điều gì nếu không có hành động mặc định, vấn đề bối cảnh. Điều gì nếu bạn chỉ quan tâm để hành động trên một vài giá trị?

Lấy ví dụ về đọc phím nhấn cho trò chơi

switch(a)
{
   case 'w':
     // Move Up
     break;
   case 's':
     // Move Down
     break;
   case 'a':
     // Move Left
     break;
   case 'd':
     // Move Right
     break;
}

Thêm:

default: // Do nothing

Chỉ là một sự lãng phí thời gian và làm tăng sự phức tạp của mã mà không có lý do.


14
Ví dụ tốt. Nhưng trên thực tế, việc thêm một mệnh đề mặc định bằng một // do nothingnhận xét đơn giản cho thấy rõ ràng là 'ok' nếu không phải tất cả các trường hợp đều được bảo vệ, trái ngược với các câu lệnh chuyển đổi khác trong đó điều này sẽ là 'không ổn'.
Nail

8
Mã hóa không chỉ là về việc xử lý một số trường hợp. Ngoài ra nó phục vụ như là một tài liệu. Bằng cách viết mặc định: và nhận xét như // Không làm gì hoặc làm gì khác, khả năng đọc mã trở nên tốt hơn.
Công viên JongAm

22
Không đồng ý với các ý kiến ​​khác. Thêm mặc định // Không có gì thêm rất ít trừ khi bạn không biết cách mã hoạt động. Tôi có thể nhìn vào một câu lệnh chuyển đổi mà không có mặc định và biết rằng mặc định là không làm gì cả. Thêm lộn xộn không làm cho điều này rõ ràng hơn.
Robert Noack

Chính xác. Đó là trong cùng một khái niệm của bàn giao al bài params. Bạn xử lý những người bạn quan tâm không phải những người khác.
Jimmy Kane

2
@jybrd Nếu bạn không tin tưởng rằng nhà phát triển trước đó đã bỏ mặc định một cách có chủ ý, tại sao bạn lại tin rằng họ đã đúng khi đưa nó vào? Một mặc định có thể vô tình trống rỗng dễ dàng như thiếu hoàn toàn. Một bình luận là không cần thiết cho một cái gì đó quá tầm thường. Đây là mã lộn xộn. Viết các bài kiểm tra đơn vị bảo hiểm đầy đủ để hiển thị ý định của bạn thay vào đó. (Chỉ là ý kiến ​​của tôi)
Robert Noack

45

KHÔNG có trường hợp mặc định thực sự có thể có lợi trong một số tình huống.

Nếu trường hợp chuyển đổi của bạn là giá trị enums, bằng cách không có trường hợp mặc định, bạn có thể nhận được cảnh báo trình biên dịch nếu bạn thiếu bất kỳ trường hợp nào. Bằng cách đó, nếu các giá trị enum mới được thêm vào trong tương lai và bạn quên thêm các trường hợp cho các giá trị này trong chuyển đổi, bạn có thể tìm hiểu về vấn đề tại thời điểm biên dịch. Bạn vẫn nên đảm bảo mã thực hiện hành động thích hợp cho các giá trị chưa được xử lý, trong trường hợp giá trị không hợp lệ được chuyển sang loại enum. Vì vậy, điều này có thể hoạt động tốt nhất cho các trường hợp đơn giản mà bạn có thể trở lại trong trường hợp enum thay vì phá vỡ.

enum SomeEnum
{
    ENUM_1,
    ENUM_2,
    // More ENUM values may be added in future
};

int foo(SomeEnum value)
{
    switch (value)
    {
    case ENUM_1:
        return 1;
    case ENUM_2:
        return 2;
    }
    // handle invalid values here
    return 0;
 }

Đây là một quan sát quan trọng! Nó thậm chí còn áp dụng nhiều hơn trong Java vì nó không cho phép bạn truyền ints vào enums.
Lii

2
Trong ví dụ của bạn, bạn có thể đưa ra một ngoại lệ thay vì quay lại sau câu lệnh switch. Theo cách đó, bạn có thể có cả trình kiểm tra tĩnh bởi trình biên dịch và nhận được một lỗi rõ ràng nếu có điều gì đó bất ngờ xảy ra.
Lii

1
Tôi đồng ý. Trong Swift trên mỗi ví dụ, chuyển đổi phải toàn diện nếu không bạn gặp lỗi trình biên dịch! Cung cấp một mặc định chỉ im lặng lỗi hữu ích này. Mặt khác, cung cấp một mặc định nếu tất cả các trường hợp được xử lý thực sự ném một cảnh báo trình biên dịch (tuyên bố không thể truy cập).
Andy

1
Chỉ cần sửa một lỗi, điều đó sẽ gây ra cảnh báo từ Trình biên dịch nếu không có mặc định: vì vậy, nói chung, Biến đổi trên enum không nên có mặc định.
notan

42

Tôi sẽ luôn sử dụng một mệnh đề mặc định, bất kể bạn đang làm việc với ngôn ngữ nào.

Những điều có thể và làm đi sai. Giá trị sẽ không như bạn mong đợi, v.v.

Không muốn bao gồm một mệnh đề mặc định ngụ ý rằng bạn tự tin rằng bạn biết tập hợp các giá trị có thể. Nếu bạn tin rằng bạn biết tập hợp các giá trị có thể sau đó, nếu giá trị nằm ngoài tập hợp các giá trị có thể này, bạn muốn được thông báo về nó - đó chắc chắn là một lỗi.

Đó là lý do tại sao bạn phải luôn sử dụng mệnh đề mặc định và đưa ra lỗi, ví dụ như trong Java:

switch (myVar) {
   case 1: ......; break;
   case 2: ......; break;
   default: throw new RuntimeException("unreachable");
}

Không có lý do để bao gồm nhiều thông tin hơn chỉ là chuỗi "không thể truy cập"; nếu điều đó thực sự xảy ra, bạn sẽ cần xem xét nguồn và giá trị của các biến, v.v. và ngăn xếp ngoại lệ sẽ bao gồm số dòng đó, vì vậy không cần phải lãng phí thời gian của bạn để viết thêm văn bản vào thông báo ngoại lệ.


39
Tôi thích throw new RuntimeException("myVar invalid " + myVar);vì điều đó có thể cung cấp cho bạn đủ thông tin để tìm ra và sửa lỗi mà không phải sử dụng trình gỡ lỗi và kiểm tra các biến, điều này có thể khó khăn nếu đây là một vấn đề hiếm khi xảy ra khó tái tạo.
Chris Dodd

1
Điều gì xảy ra nếu đó không phải là một điều kiện lỗi cho giá trị không khớp với một trong các trường hợp?
Gabe

4
Nếu đó không phải là một điều kiện lỗi, thì sẽ không cần a default:. Nhưng thường thì không, người ta bỏ mặc định vì người ta nghĩ myVarkhông bao giờ có bất kỳ giá trị nào ngoài những giá trị được liệt kê; tuy nhiên tôi không thể đếm số lần tôi đã ngạc nhiên trong cuộc sống thực khi biến đó có một giá trị khác với các giá trị mà nó "có thể" có thể có. Trong những trường hợp đó, tôi rất biết ơn về ngoại lệ khiến tôi thấy điều đó ngay lập tức, thay vì gây ra một số lỗi khác sau đó (khó gỡ lỗi hơn) hoặc trả lời sai (có thể bị bỏ qua trong thử nghiệm).
Adrian Smith

2
Tôi đồng ý với Adrian. Thất bại khó khăn và thất bại sớm.
Slappy

Tôi thích ném một AssertionErrorthay vì RuntimeException, vì tình huống này rất giống với một khẳng định nói rằng đó myVarlà một trong những giá trị được xử lý. Ngoài ra cơ hội để ai đó bắt và nuốt lỗi là nhỏ hơn.
Phi-líp

15

Trong công ty của tôi, chúng tôi viết phần mềm cho thị trường Avionics and Defense và chúng tôi luôn bao gồm một tuyên bố mặc định, bởi vì TẤT CẢ các trường hợp trong một tuyên bố chuyển đổi phải được xử lý rõ ràng (ngay cả khi đó chỉ là một nhận xét 'Không làm gì cả'). Chúng tôi không thể đủ khả năng cho phần mềm chỉ hoạt động sai hoặc đơn giản là gặp sự cố với các giá trị không mong muốn (hoặc thậm chí là những gì chúng tôi nghĩ là không thể).

Có thể thảo luận rằng một trường hợp mặc định không phải lúc nào cũng cần thiết, nhưng bằng cách luôn luôn yêu cầu nó, nó dễ dàng được kiểm tra bởi các máy phân tích mã của chúng tôi.


1
Tôi có cùng yêu cầu nơi tôi làm việc; chúng tôi viết mã cho nhúngContContersers phải vượt qua kiểm tra an toàn nghiêm ngặt và thường phải chịu EMI. Sẽ là vô trách nhiệm khi cho rằng một biến liệt kê sẽ không bao giờ có giá trị không có trong danh sách liệt kê.
oosterwal

12

Câu lệnh "switch" phải luôn bao gồm một mệnh đề mặc định? Không. Nó thường bao gồm một mặc định.

Bao gồm một mệnh đề mặc định chỉ có ý nghĩa nếu có gì đó để làm, chẳng hạn như xác nhận một điều kiện lỗi hoặc cung cấp một hành vi mặc định. Bao gồm một "chỉ vì" là lập trình tôn giáo hàng hóa và không cung cấp giá trị. Đó là "công tắc" tương đương với việc nói rằng tất cả các câu lệnh "nếu" phải bao gồm một "khác".

Đây là một ví dụ tầm thường về nơi nó không có ý nghĩa:

void PrintSign(int i)
{
    switch (Math.Sign(i))
    {
    case 1:
        Console.Write("positive ");
        break;
    case -1:
        Console.Write("negative ");
        break;
    default: // useless
    }
    Console.Write("integer");
}

Điều này tương đương với:

void PrintSign(int i)
{
    int sgn = Math.Sign(i);
    if (sgn == 1)
        Console.Write("positive ");
    else if (sgn == -1)
        Console.Write("negative ");
    else // also useless
    {
    }
    Console.Write("integer");
}

Tôi không đồng ý. IMHO, lần duy nhất không nên tồn tại mặc định là nếu không có cách nào, bây giờ và mãi mãi, bộ đầu vào có thể thay đổi và bạn có mọi giá trị có thể được bảo hiểm. Trường hợp đơn giản nhất tôi có thể nghĩ đến là một giá trị boolean từ cơ sở dữ liệu, trong đó các câu trả lời duy nhất (cho đến khi SQL thay đổi!) Là đúng, sai và NULL. Trong mọi trường hợp khác, có một mặc định với một xác nhận hoặc ngoại lệ "Không nên xảy ra!" có ý nghĩa tốt Nếu mã của bạn thay đổi và bạn có một hoặc nhiều giá trị mới, thì bạn có thể đảm bảo mã cho chúng và các thử nghiệm của bạn sẽ nổ tung nếu bạn không.
Harper Shelby

4
@Harper: Ví dụ của bạn thuộc danh mục "khẳng định điều kiện lỗi".
Gabe

Tôi khẳng định rằng ví dụ của tôi là chuẩn mực, và số lượng nhỏ các trường hợp mà người ta có thể chắc chắn 100% mọi trường hợp có thể được bảo hiểm và một mặc định không cần thiết là ngoại lệ. Câu trả lời của bạn được diễn đạt theo cách khiến nó phát ra âm thanh (ít nhất là với tôi) như thể mặc định không có gì sẽ xảy ra thường xuyên hơn không.
Harper Shelby

@Harper: OK, tôi đã thay đổi từ ngữ để chỉ ra rằng tình huống không làm gì là ít phổ biến hơn.
Gabe

4
Tôi nghĩ rằng default:trong những trường hợp đó mã hóa các giả định của bạn. Ví dụ, có ổn không khi sgn==0in integer(không dương hay âm), hay đó là lỗi? Đối với tôi đọc mã đó, thật khó để nói. Tôi cho rằng bạn muốn viết zerotrong trường hợp đó thì không integer, và lập trình viên đưa ra giả định sgnchỉ có thể là -1 hoặc +1. Nếu đó là trường hợp, có default:sẽ cho phép lập trình viên sớm nhận được lỗi giả định và thay đổi mã.
Adrian Smith

7

Theo như tôi thấy thì câu trả lời là 'mặc định' là tùy chọn, nói rằng một công tắc phải luôn chứa một mặc định giống như nói mọi 'if-otherif' phải chứa một 'khác'. Nếu có một logic được thực hiện theo mặc định, thì câu lệnh 'mặc định' sẽ ở đó, nhưng nếu không thì mã có thể tiếp tục thực thi mà không làm gì cả.


6

Có một mệnh đề mặc định khi nó không thực sự cần thiết là lập trình phòng thủ Điều này thường dẫn đến mã quá phức tạp do quá nhiều mã xử lý lỗi. Mã xử lý và phát hiện lỗi này gây hại cho khả năng đọc mã, khiến việc bảo trì khó khăn hơn và cuối cùng dẫn đến nhiều lỗi hơn nó giải quyết.

Vì vậy, tôi tin rằng nếu không đạt được mặc định - bạn không cần phải thêm nó.

Lưu ý rằng "không nên đạt được" có nghĩa là nếu nó đạt đến thì đó là một lỗi trong phần mềm - bạn cần kiểm tra các giá trị có thể chứa các giá trị không mong muốn do đầu vào của người dùng, v.v.


3
Một lý do phổ biến khác để nhận các trường hợp bất ngờ: Các phần khác của mã được sửa đổi, có lẽ nhiều năm sau đó.
Hendrik Brummermann

Thật vậy, đây là hành vi rất nguy hiểm. Ít nhất, tôi sẽ thêm một mệnh đề assert (). Sau đó, nó dễ dàng được phát hiện bất cứ khi nào có lỗi.
Kurt Pattyn

5

Tôi sẽ nói rằng nó phụ thuộc vào ngôn ngữ, nhưng trong C nếu bạn đang chuyển sang loại enum và bạn xử lý mọi giá trị có thể, thì có lẽ tốt hơn là bạn KHÔNG bao gồm trường hợp mặc định. Bằng cách đó, nếu bạn thêm một thẻ enum bổ sung sau đó và quên thêm nó vào công tắc, một trình biên dịch có thẩm quyền sẽ đưa ra cảnh báo về trường hợp mất tích.


5
"Mọi giá trị có thể" dường như không được xử lý bằng enum. Bạn có thể truyền một số nguyên cho một enum ngay cả khi giá trị cụ thể đó không được xác định rõ ràng. Và trình biên dịch nào cảnh báo về trường hợp mất tích?
TrueWill

1
@TrueWill: Có, bạn có thể sử dụng các phôi rõ ràng để viết mã bị che giấu không thể hiểu được; để viết mã dễ hiểu, bạn nên tránh điều đó. gcc -Wall(loại mẫu số chung thấp nhất của trình biên dịch có thẩm quyền) đưa ra cảnh báo về các enum chưa được xử lý trong các câu lệnh chuyển đổi.
Chris Dodd

4

Nếu bạn biết rằng câu lệnh chuyển đổi sẽ chỉ có một bộ nhãn hoặc giá trị được xác định nghiêm ngặt, chỉ cần làm điều này để bao gồm các cơ sở, theo cách đó bạn sẽ luôn nhận được kết quả hợp lệ .. Chỉ cần đặt mặc định trên nhãn sẽ lập trình / logic là người xử lý tốt nhất cho các giá trị khác.

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}

Là đại tràng sau khi defaultvẫn còn yêu cầu ở đây? Hoặc làm điều này cho phép một số cú pháp đặc biệt cho phép bạn bỏ qua nó?
Ponkadoodle

Dấu hai chấm là bắt buộc, đó là một lỗi đánh máy, cảm ơn bạn đã mang nó đến sự chú ý của tôi.
deegee

3

Atleast nó không bắt buộc trong Java. Theo JLS, nó cho biết tối đa một trường hợp mặc định có thể có mặt. Có nghĩa là không có trường hợp mặc định là chấp nhận được. Đôi khi nó cũng phụ thuộc vào ngữ cảnh mà bạn đang sử dụng câu lệnh switch. Ví dụ: trong Java, khối chuyển đổi sau không yêu cầu trường hợp mặc định

private static void switch1(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        break;
    case "Tuesday":
        System.out.println("Tuesday");
        break;
    }
}

Nhưng trong phương thức sau đây sẽ trả về Chuỗi, trường hợp mặc định có ích để tránh lỗi biên dịch

    private static String switch2(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        return name;

    case "Tuesday":
        System.out.println("Tuesday");
        return name;

    default:
        return name;
    }
}

mặc dù bạn có thể tránh lỗi biên dịch cho phương thức trên mà không gặp trường hợp mặc định bằng cách chỉ có câu lệnh return ở cuối, nhưng việc cung cấp trường hợp mặc định sẽ khiến nó dễ đọc hơn.


3

Một số nguyên tắc (lỗi thời) nói như vậy, chẳng hạn như MISRA C :

Yêu cầu cho một điều khoản mặc định cuối cùng là lập trình phòng thủ. Điều khoản này sẽ có hành động thích hợp hoặc có một nhận xét phù hợp về lý do tại sao không có hành động nào được thực hiện.

Lời khuyên đó đã lỗi thời vì nó không dựa trên các tiêu chí hiện có liên quan. Thiếu sót rõ ràng là những gì Harlan Kassler nói:

Thoát khỏi trường hợp mặc định cho phép trình biên dịch tùy chọn cảnh báo hoặc thất bại khi thấy trường hợp chưa xử lý. Xác minh tĩnh sau tất cả tốt hơn bất kỳ kiểm tra động nào, và do đó không phải là sự hy sinh xứng đáng khi bạn cần kiểm tra động.

Như Harlan cũng đã chứng minh, chức năng tương đương của trường hợp mặc định có thể được tạo lại sau khi chuyển đổi. Đó là chuyện nhỏ khi mỗi trường hợp là một sự trở lại sớm.

Nhu cầu điển hình cho kiểm tra động là xử lý đầu vào, theo nghĩa rộng. Nếu một giá trị đến từ bên ngoài sự kiểm soát của chương trình, nó không thể được tin cậy.

Đây cũng là nơi Misra có quan điểm lập trình phòng thủ cực đoan, theo đó, miễn là giá trị không hợp lệ có thể biểu thị được thì phải kiểm tra, bất kể chương trình có chính xác hay không. Điều này có ý nghĩa nếu phần mềm cần phải đáng tin cậy nhất có thể khi có lỗi phần cứng. Nhưng như Ophir Yoktan đã nói, hầu hết các phần mềm đều tốt hơn là không "xử lý" các lỗi. Việc thực hành thứ hai đôi khi được gọi là lập trình tấn công .


2

Bạn nên có một mặc định để bắt các giá trị không mong đợi đến.

Tuy nhiên, tôi không đồng ý với Adrian Smith rằng thông báo lỗi của bạn theo mặc định sẽ là một cái gì đó hoàn toàn vô nghĩa. Có thể có một trường hợp chưa được xử lý mà bạn không thấy trước (đó là vấn đề quan trọng) rằng người dùng của bạn cuối cùng sẽ nhìn thấy và một thông báo như "không thể truy cập" là hoàn toàn vô nghĩa và không giúp được ai trong tình huống đó.

Trường hợp cụ thể, bạn đã có một BSOD hoàn toàn vô nghĩa bao nhiêu lần? Hoặc một ngoại lệ gây tử vong @ 0x352FBB3C32342?


ví dụ: hãy nhớ rằng không chỉ nhà phát triển luôn nhìn thấy các thông báo lỗi. Chúng ta sống trong thế giới thực, mọi người phạm sai lầm.
John Hunt

2

Nếu giá trị chuyển đổi ( switch (biến )) không thể đạt đến trường hợp mặc định, thì trường hợp mặc định hoàn toàn không cần thiết. Ngay cả khi chúng tôi giữ trường hợp mặc định, nó hoàn toàn không được thực thi. Đó là mã chết.


2

Nó là một 'quy ước' mã hóa tùy chọn. Tùy thuộc vào việc sử dụng là có cần thiết hay không. Cá nhân tôi tin rằng nếu bạn không cần thì nó không nên ở đó. Tại sao bao gồm một cái gì đó sẽ không được sử dụng hoặc đạt được bởi người dùng?

Nếu các khả năng trường hợp bị giới hạn (tức là Boolean) thì mệnh đề mặc định là không cần thiết !


2

Nếu không có trường hợp mặc định trong một switchtuyên bố, hành vi có thể không dự đoán được nếu trường hợp đó phát sinh tại một số thời điểm, không thể dự đoán được ở giai đoạn phát triển. Đó là một thực hành tốt để bao gồm một defaulttrường hợp.

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

Việc thực hành như vậy có thể dẫn đến một lỗi như sự thiếu sót của NULL , rò rỉ bộ nhớ cũng như các loại lỗi nghiêm trọng khác .

Ví dụ, chúng tôi giả sử rằng mỗi điều kiện khởi tạo một con trỏ. Nhưng nếu defaulttrường hợp được cho là phát sinh và nếu chúng ta không khởi tạo trong trường hợp này, thì có mọi khả năng hạ cánh với một ngoại lệ con trỏ null. Do đó, nên sử dụng một defaulttuyên bố trường hợp, mặc dù nó có thể là tầm thường.


2

Trường hợp mặc định có thể không cần thiết trong công tắc được sử dụng bởi enum. khi switch chứa tất cả giá trị, trường hợp mặc định sẽ không bao giờ thực thi. Vì vậy, trong trường hợp này, nó là không cần thiết.


1

Phụ thuộc vào cách chuyển đổi trong ngôn ngữ cụ thể hoạt động, tuy nhiên trong hầu hết các ngôn ngữ khi không có trường hợp nào khớp, việc thực thi rơi vào câu lệnh chuyển đổi mà không có cảnh báo. Hãy tưởng tượng bạn mong đợi một số bộ giá trị và xử lý chúng trong chuyển đổi, tuy nhiên bạn sẽ nhận được một giá trị khác trong đầu vào. Không có gì xảy ra và bạn không biết không có gì xảy ra. Nếu bạn bắt gặp trường hợp mặc định, bạn sẽ biết có gì đó không đúng.


1

Tôi không đồng ý với câu trả lời được bình chọn nhiều nhất của Vanwaril ở trên.

Bất kỳ mã nào thêm phức tạp. Ngoài ra các bài kiểm tra và tài liệu phải được thực hiện cho nó. Vì vậy, nó luôn luôn tốt nếu bạn có thể lập trình bằng cách sử dụng ít mã hơn. Ý kiến ​​của tôi là tôi sử dụng mệnh đề mặc định cho câu lệnh chuyển đổi không toàn diện trong khi tôi không sử dụng mệnh đề mặc định cho câu lệnh chuyển đổi toàn diện. Để chắc chắn rằng tôi đã làm đúng, tôi sử dụng một công cụ phân tích mã tĩnh. Vì vậy, hãy đi vào chi tiết:

  1. Các câu lệnh chuyển đổi không toàn diện: Chúng phải luôn có giá trị mặc định. Như tên cho thấy đó là những tuyên bố không bao gồm tất cả các giá trị có thể. Điều này cũng có thể không khả thi, ví dụ: câu lệnh chuyển đổi trên một giá trị số nguyên hoặc trên Chuỗi. Ở đây tôi muốn sử dụng ví dụ về Vanwaril (Cần đề cập rằng tôi nghĩ rằng anh ta đã sử dụng ví dụ này để đưa ra một gợi ý sai. Tôi sử dụng nó ở đây để nêu ngược lại -> Sử dụng một tuyên bố mặc định):

    switch(keystroke)
    {
      case 'w':
        // move up
      case 'a':
        // move left
      case 's':
        // move down
      case 'd':
        // move right
      default:          
        // cover all other values of the non-exhaustive switch statement
    }
    

    Người chơi có thể nhấn bất kỳ phím nào khác. Sau đó, chúng tôi không thể làm bất cứ điều gì (điều này có thể được hiển thị trong mã chỉ bằng cách thêm một nhận xét vào trường hợp mặc định) hoặc ví dụ như nó sẽ in một cái gì đó trên màn hình. Trường hợp này có liên quan vì nó có thể xảy ra.

  2. Các câu lệnh chuyển đổi toàn diện: Các câu lệnh chuyển đổi này bao gồm tất cả các giá trị có thể, ví dụ: một câu lệnh chuyển đổi trên bảng liệt kê các loại hệ thống cấp. Khi phát triển mã lần đầu tiên, nó dễ dàng bao gồm tất cả các giá trị. Tuy nhiên, vì chúng ta là con người nên có một cơ hội nhỏ để quên đi một số. Ngoài ra, nếu bạn thêm một giá trị enum sau đó để tất cả các câu lệnh chuyển đổi phải được điều chỉnh để làm cho chúng hoàn toàn một lần nữa sẽ mở đường dẫn đến địa ngục lỗi. Giải pháp đơn giản là một công cụ phân tích mã tĩnh. Công cụ nên kiểm tra tất cả các câu lệnh chuyển đổi và kiểm tra xem chúng có đầy đủ không hoặc nếu chúng có giá trị mặc định. Dưới đây là một ví dụ cho một tuyên bố chuyển đổi toàn diện. Đầu tiên chúng ta cần một enum:

    public enum GradeSystemType {System1To6, SystemAToD, System0To100}
    

    Sau đó, chúng ta cần một biến của enum này như thế nào GradeSystemType type = .... Một tuyên bố chuyển đổi đầy đủ sau đó sẽ trông như thế này:

    switch(type)
    {
      case GradeSystemType.System1To6:
        // do something
      case GradeSystemType.SystemAToD:
        // do something
      case GradeSystemType.System0To100:
        // do something
    }
    

    Vì vậy, nếu chúng ta mở rộng GradeSystemTypebằng ví dụ System1To3, công cụ phân tích mã tĩnh sẽ phát hiện ra rằng không có mệnh đề mặc định và câu lệnh switch không đầy đủ để chúng ta lưu lại.

Chỉ cần một điều bổ sung. Nếu chúng ta luôn sử dụng một defaultmệnh đề thì có thể xảy ra rằng công cụ phân tích mã tĩnh không có khả năng phát hiện các câu lệnh chuyển đổi toàn diện hoặc không toàn diện vì nó luôn phát hiện defaultmệnh đề. Điều này là rất tệ vì chúng tôi sẽ không được thông báo nếu chúng tôi mở rộng enum bằng một giá trị khác và quên thêm nó vào một câu lệnh chuyển đổi.


0

Các câu lệnh chuyển đổi luôn chứa một mệnh đề mặc định? Không có trường hợp chuyển đổi nào có thể tồn tại với trường hợp mặc định, trong trường hợp chuyển đổi trường hợp mặc định sẽ kích hoạt giá trị chuyển đổi switch(x)trong trường hợp này x khi không khớp với bất kỳ giá trị trường hợp nào khác.


0

Tôi tin rằng đây là ngôn ngữ khá cụ thể và đối với trường hợp C ++, một điểm nhỏ cho loại lớp enum . Mà xuất hiện an toàn hơn C enum truyền thống. NHƯNG

Nếu bạn nhìn vào việc thực hiện std :: byte thì nó giống như:

enum class byte : unsigned char {} ;

Nguồn: https://en.cppreference.com/w/cpp/lingu/enum

Và cũng xem xét điều này:

Mặt khác, nếu T là loại liệt kê có phạm vi hoặc không có phạm vi với loại cơ bản cố định và nếu danh sách khởi tạo chỉ có một trình khởi tạo và nếu chuyển đổi từ trình khởi tạo sang loại cơ bản là không thu hẹp, và nếu việc khởi tạo là khởi tạo danh sách trực tiếp, sau đó phép liệt kê được khởi tạo với kết quả chuyển đổi trình khởi tạo thành kiểu cơ bản của nó.

(kể từ C ++ 17)

Nguồn: https://en.cppreference.com/w/cpp/lingu/list_initialization

Đây là một ví dụ về lớp enum đại diện cho các giá trị không được xác định là liệt kê. Vì lý do này, bạn không thể đặt niềm tin hoàn toàn vào enums. Tùy thuộc vào ứng dụng này có thể quan trọng.

Tuy nhiên, tôi thực sự thích những gì @Harlan Kassler đã nói trong bài đăng của mình và sẽ bắt đầu sử dụng chiến lược đó trong một số tình huống.

Chỉ là một ví dụ về lớp enum không an toàn:

enum class Numbers : unsigned
{
    One = 1u,
    Two = 2u
};

int main()
{
    Numbers zero{ 0u };
    return 0;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.