폴 스루 스위치 문의 적절한 사용


14

폴 스루 (클래식) 스위치 문을 사용하는 것이 언제 적절한가요? 그러한 사용을 권장하고 권장합니까 아니면 모든 비용을 피해야합니까?


모든 언어가 switch 문에 대한 통과를 허용하지는 않습니다.
Oded

@Oded, 편집, "고전적인"단어 추가. 모든 언어를 통해 떨어질 수, 그럼에도 불구하고 나는 그것이 고전)입니다 주장
shabunc

3
더프의 장치 에 대해 이야기하고 있다면 그 중 하나입니다.
Oded

6
@Oded : 대부분의 사람들이 가장 먼저 생각하는 것은 아니지만 "적절한"것은 아닙니다. 에 따르면 , 더프 자신 말했다 "이것은 확실히 스위치는 기본적으로 통해 가을할지 여부를 논의의 인수를 제공하지만, 인수 또는 반대의 경우 잘 모르겠어요."
BlueRaja-대니 Pflughoeft

답변:


15

다음은 유용한 예입니다.

public Collection<LogItems> GetAllLogItems(Level level) {
    Collection<LogItems> result = new Collection<LogItems>();
    switch (level) {
        // Note: fall through here is INTENTIONAL
        case All:
        case Info:
             result.Add(GetItemsForLevel(Info));
        case Warning:
             result.Add(GetItemsForLevel(Warning));
        case Error:
             result.Add(GetItemsForLevel(Error));
        case Critical:
             result.Add(GetItemsForLevel(Critical));
        case None:
    }
    return result;
}

이런 종류의 것 (하나의 경우가 다른 경우를 포함하는 경우)은 드물기 때문에 일부 새로운 언어에서는 대체를 허용하지 않거나 특별한 구문이 필요합니다.


13
이 예제는 흥미롭지 만 필수 전체 // INTENTIONAL FALL THROUGH HERE설명 이 부족합니다 .
Russell Borogove

GetItemsForLevel(Info)호출을 호출하는 GetItemsForLevel(Warning)등의 방법 으로이 코드를 작성하는 것도 쉽습니다 .
Caleb

@RussellBorogove : 물론 맞습니다.
구성자

@Caleb :이 경우에 그렇습니다. 그러나 통화가 조금 더 복잡하다면 어떨까요? 약간 털이 나올 수 있지만 넘어지면 단순 해 보입니다. 나는 실제로 쓰루 스루를 선호하는 것이 아니라 특정 상황에서 유용 할 수 있다고 말하고 있습니다.
구성자

가장 좋은 예는 아닙니다. 경고 수준의 순서가 있습니다. 그 순서를 정의함으로써,이 방법은 아이템 레벨이 적어도 원하는 레벨과 동일 할 때 아이템을 필터링하는 단일 코드 라인으로 줄어든다.
kevin cline

8

특정 기능을 둘 이상의 값에 적용해야 할 때 사용합니다. 예를 들어 operationCode라는 속성을 가진 개체가 있다고 가정합니다. 코드가 1, 2, 3 또는 4와 같으면 OperationX ()를 시작하려고합니다. 5 또는 6이면 OperationY ()를 시작하고 7을 시작하고 OperationZ ()를 시작하십시오. 폴 스루 (fall-through)를 사용할 수있는 7 가지 기능과 기능을 갖춘 완벽한 사례가있는 이유는 무엇입니까?

특정 상황에서, 특히 100 개의 if-else 문을 피하는 경우 완전히 유효하다고 생각합니다. =)


4
당신이 설명하는 것은 동일한 코드에 묶인 switch여러 개 case입니다. 이는 하나의 실행이 case다음의 부족으로 인해 다음 실행으로 계속되는 대체와 다릅니다 break.
Blrfl

3
실제로는 중요하지 않습니다.이 오류는 중단 설명이 없기 때문에 다음 경우로 넘어집니다.
Yatrix

그 답을 반영하기 위해 귀하의 답변에 시나리오를 다시 작성하겠습니다.
Blrfl

2
@Yatrix : 동의하지 않습니다. 연속 된 사례가 모두 중단을 생략하는 것과 정확히 동일한 코드 블록을 실행하는 것은 매우 다릅니다. 하나는 일상적인 것이고 다른 하나는 그것과는 거리가 멀다 (ime).
quentin-starin

3
@qes 예, 다릅니다. 그러나 둘 다 실패입니다. 언제 적절한 지 물었다. 나는 언제 그런지 예를 들었다. 포괄적 인 예가 아니 었습니다. 언어에 따라 넘어지기 전에 설명이 작동하지 않을 수 있습니다. 나는 그것이 C # stackoverflow.com/questions/174155/…
Yatrix

8

나는 때때로 그것들을 사용했는데, 나는 항상 적절한 사용법이라고 생각하지만 적절한 의견에 포함되었을 때만.


7

추락 사례는 완벽하게 좋습니다. 열거 형이 많은 곳에서 사용되는 경우가 종종 있으며, 경우를 구분할 필요가없는 경우 대체 논리를 사용하는 것이 더 쉽다는 것을 알았습니다.

예를 들어 (설명 주석을 참고하십시오) :

public boolean isAvailable(Server server, HealthStatus health) {
  switch(health) {
    // Equivalent positive cases
    case HEALTHY:
    case UNDER_LOAD:
      return true;

    // Equivalent negative cases
    case FAULT_REPORTED:
    case UNKNOWN:
    case CANNOT_COMMUNICATE:
      return false;

    // Unknown enumeration!
    default:
      LOG.warn("Unknown enumeration " + health);
      return false;
  }
}

나는 이런 종류의 사용이 완벽하게 수용 가능하다는 것을 알았습니다.


case X: case Y: doSomething()와 사이에는 큰 차이가 case X: doSomething(); case Y: doAnotherThing()있습니다. 첫 번째, 의도는 명백하고, 두 번째 의도는 의도적이거나 그렇지 않을 수 있습니다. 내 경험상 첫 번째 예제는 컴파일러 / 코드 분석기에서 경고를 트리거하지 않지만 두 번째 예제는 경고를 트리거하지 않습니다. 개인적으로, 나는 "공식적인"정의에 대해 확신 할 수없는 두 번째 예를 "통과"라고 부릅니다.
Jens Bannmann

6

그것은에 달려 있습니다 :

  • 당신의 개인적인 취향
  • 고용주의 코딩 표준
  • 관련된 위험 량

한 사례가 다음 사례로 넘어가는 것과 관련된 두 가지 주요 문제는 다음과 같습니다.

  1. 코드가 case 문의 순서에 따라 달라집니다. 당신이 결코 빠져들지 않는다면 그것은 사실이 아니며, 종종 환영받지 못하는 복잡성을 추가합니다.

  2. 하나의 사례에 대한 코드에 하나 이상의 후속 사례에 대한 코드가 포함되어 있는지 확실하지 않습니다.

어떤 곳은 넘어지는 것을 명시 적으로 금지합니다. 그런 곳에서 일하지 않고 연습에 익숙하고 문제의 코드를 깨뜨려도 큰 고통을 겪지 않는다면 세계에서 최악의 일은 아닐 수도 있습니다. 하지만 그렇게한다면, 나중에 오는 사람들 (미래를 포함하여)에게 경고하기 위해주의를 끄는 논평을 가까운 곳에 두십시오.


4

다음은 내 인생을 더 단순하게 만드는 추락의 빠른 (완전히 불완전한 (윤년의 특별한 처리 없음)) 예입니다.

function get_julian_day (date) {
    int utc_date = date.getUTCDate();
    int utc_month = date.getUTCMonth();

    int julian_day = 0;

    switch (utc_month) {
        case 11: julian_day += 30;
        case 10: julian_day += 31;
        case 9:  julian_day += 30;
        case 8:  julian_day += 31;
        case 7:  julian_day += 31;
        case 6:  julian_day += 30;
        case 5:  julian_day += 31;
        case 4:  julian_day += 30;
        case 3:  julian_day += 31;
        case 2:  julian_day += 28;
        case 1:  julian_day += 31;
        default: break;
    }

    return julian_day + utc_date;
}

5
이것은 영리한 일이지만, 이렇게하는 것에서 절약하는 시간은 다른 사람들이이 일을 이해하는 데 걸리는 시간보다 훨씬 중요합니다. 또한 폴 스루 측면을 제거하여 더 나은 성능을 얻을 수 있습니다. 즉 31 + 28 + 31은 항상 90입니다.이 작업을 수행하려는 경우 고려할 11 개만 있으므로 총계를 사례에 넣을 수도 있습니다.
JimmyJames

네 말이 맞아, 내 예는 확실히 고안되었다.)하지만 말할 것입니다. 그러나 스위치의 각 경우에 대해 모든 누적 일을 미리 계산하는 대신 일 수를 철자하면 숨겨진 버그를 발견하는 것이 더 쉽습니다. .
AaronDanielson

2
나는 당신에게 그것을 줄 것이다. 그러나 지속적인 선언으로하는 것이 바람직 할 것이다. 예 : FEB_START = 31; MAR_START = FEB_START + 28; 등이 어떤 언어인지 확실하지 않지만 많은 언어에서 컴파일 타임에 계산됩니다. 여기서 가장 큰 문제는 약간 둔감하다는 것입니다. 그렇게 비정형적인 것은 나쁜 생각이 아닙니다. 큰 이점이 없다면 일반적으로 일반적인 관용구를 고수하는 것이 좋습니다.
JimmyJames

1
이 예제에서 시작 날짜에 상수를 사용하는 훌륭한 대안입니다. 어쨌든, 여기서 중요한 점은 누적 합계가 스위치 케이스 폴 스루에 크게 사용된다는 것입니다. 나는 일반적인 관용구를 사용하는 것에 100 % 동의하지만,이 질문의 본질은 일반적인 관용구가 나오기 어려운 좀 더 난해한 특징으로 통하는 것입니다.
AaronDanielson 18

3

한 사례에서 다른 사례로 갈 필요가 있다고 느낀다면 (드물게, 물론), 나는 goto case당신의 언어가 그것을 지원한다고 가정합니다.

쓰루를 통해 떨어지는 것은 매우 드문 일이며 코드를 읽는 동안 간과하기가 매우 쉽기 때문에 명시 적 인 것이 적절하다고 생각합니다.

또한 case 문을 다시 정렬 할 때 발생할 수있는 버그를 피하는 데 도움이됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.