조건부? :( 삼항) 연산자 사용의 이점


101

표준 if-else 문과 달리? : 연산자의 장점과 단점은 무엇입니까? 명백한 것은 :

조건부? : 연산자

  • 직접 값 비교 및 ​​할당을 처리 할 때 더 짧고 간결합니다.
  • if / else 구조만큼 유연하지 않은 것 같습니다.

표준 If / Else

  • 더 많은 상황에 적용 가능 (예 : 함수 호출)
  • 종종 불필요하게 길다

가독성은 진술에 따라 각기 다른 것처럼 보입니다. ? : 연산자에 처음 노출 된 후 잠시 동안 정확히 어떻게 작동하는지 이해하는 데 시간이 걸렸습니다. 가능한 한 그것을 사용하거나 프로그래머가 아닌 많은 사람들과 함께 일한다는 점을 감안할 때 if / else를 고수하는 것이 좋습니다.


8
당신은 이미 그것의 요지를 가지고 있습니다.
Byron Whitlock

1
@Nicholas Knight : OP는 할 수 없다는 것을 의미한다고 생각합니다. 예를 들어 SomeCheck() ? DoFirstThing() : DoSecondThing();값을 반환하려면 표현식을 사용해야합니다.
Dan Tao

6
명확한 곳에서 사용하고 그렇지 않은 경우 if / else를 고수하십시오. 코드 명확성이 주요 고려 사항이어야합니다.
hollsk

8
'??'봤어? 아직? 당신이 생각하는 경우에 진심으로, ternaries 멋진 ...입니다
PDR

3
많은 사람들처럼 단순히 "삼항 연산자"라고 부르지 않는 것에 +1. C #에서 유일한 삼항 연산자 (단항 및 이진과 반대)이지만 이름이 아닙니다.
John M Gant

답변:


122

기본적으로 결과 문이 매우 짧고 가독성을 희생하지 않고 if / else 등가물에 비해 간결성이 크게 증가한 경우에만 사용하는 것이 좋습니다.

좋은 예 :

int result = Check() ? 1 : 0;

나쁜 예 :

int result = FirstCheck() ? 1 : SecondCheck() ? 1 : ThirdCheck() ? 1 : 0;

5
좋은 전화이지만 기록을 위해 그것은 "간결"입니다.
mqp


39
나는 항상 간단한 것으로 시작하여 완전히 읽을 수 없을 때까지 시간이 지남에 따라 더 복잡하게 만듭니다.
Jouke van der Maas

9
두 번째 예의 가독성은 더 나은 형식으로 쉽게 수정할 수 있습니다. 그러나 OP가 권장하는 것처럼 가독성과 간결함 대 자세한 정보가 있습니다.
Nathan Ernst

4
OP 질문의 일부는 아니지만 중요한 것은 return삼항 연산의 결과에 포함될 수 없다는 사실입니다 . 예 : check() ? return 1 : return 0;작동하지 않지만 작동 return check() ? 1 : 0;합니다. 프로그래밍에서 이러한 작은 특징을 찾는 것은 항상 재미 있습니다.
CSS

50

이것은 다른 답변에서 거의 다뤄지지 만 "표현식"은 그것이 왜 그렇게 유용한 지 설명하지 않습니다.

C ++ 및 C #과 같은 언어에서는이를 사용하여 로컬 읽기 전용 필드 (메서드 본문 내)를 정의 할 수 있습니다. 읽기 전용 필드의 값이 단일 명령문 내에서 지정되어야하므로 기존의 if / then 명령문으로는 불가능합니다.

readonly int speed = (shiftKeyDown) ? 10 : 1;

다음과 같지 않습니다.

readonly int speed;  
if (shifKeyDown)  
    speed = 10;    // error - can't assign to a readonly
else  
    speed = 1;     // error  

비슷한 방법으로 다른 코드에 3 차 표현식을 포함 할 수 있습니다. 소스 코드를 더 간결하게 만들뿐만 아니라 (결과적으로 더 읽기 쉬운 경우도 있음) 생성 된 기계어 코드를 더 간결하고 효율적으로 만들 수도 있습니다.

MoveCar((shiftKeyDown) ? 10 : 1);

... 같은 메서드를 두 번 호출하는 것보다 적은 코드를 생성 할 수 있습니다.

if (shiftKeyDown)
    MoveCar(10);
else
    MoveCar(1);

물론 더 편리하고 간결한 형식이기도합니다 (입력이 적고 반복이 적으며 if / else에서 코드 청크를 복제해야하는 경우 오류 가능성을 줄일 수 있음). 다음과 같은 깨끗한 "일반적인 패턴"사례에서 :

object thing = (reference == null) ? null : reference.Thing;

... 읽고 / 파싱 / 이해하는 것이 (한 번 익숙해지면) 장황한 if / else 등가물보다 빠르기 때문에 코드를 더 빨리 'grok'하는 데 도움이 될 수 있습니다.

물론 유용하다고 해서 모든 경우 에 사용 하는 것이 가장 좋은 것은 아닙니다 . 의미를 사용하여 투명 (또는 더 명확하게) 어디 코드의 짧은 비트를 위해 그것을 사용하는 경우에만 좋을 걸 ?:좀 더 복잡한 코드를 사용하는 경우, 또는 서로 내에 중첩의 원 사업자는 읽기 코드가 끔찍하게 어렵게 만들 수 있습니다 - .


@JaminGrey "이것은 상수가 생성 될 때 10 또는 1로 설정된다는 의미가 아닙니다." 당신은 의미합니까를 하지 평균 있다고? 잘못된 주석은 해결하려는 문제보다 새로운 C ++ 프로그래머에게 더 많은 혼란을 줄 수 있습니다.)
Clonkex

5
미래의 독자를 위해 " const int speed = (shiftKeyDown)? 10 : 1; "은 상수 가 처음 생성 될 때 10 또는 1로 설정 됨을 의미합니다. 매번 의미하는 것은 아닙니다. 상수에 액세스하면 검사를 수행합니다. (그냥은 새로운 C ++ 프로그래머가 혼동되었다 넣다)
야민 회색

2
... 또는 다르게 말하면 a const는 상수입니다. 즉, 선언 된 명령문이 실행 된 후에는 변경할 수 없습니다.
Jason Williams

1
@JaminGrey. 그래야하지 readonly않습니까? 나는 항상 const" 컴파일 시간에 해결되고 사용되는 곳마다 인라인"을 의미 한다고 생각 했습니다 .
Nolonar

1
@ColinWiseman, 그것은이다 : 방법을 설명 할 수 있습니다 사용. 나는 당신이 그것을 할 수 있다고해서 그것이 어떤 특정한 경우에 반드시 "가장 좋은"일이라는 것을 의미하지는 않는다고 구체적으로 말한다. 이를 해결하기 위해 독자는 자신에게 유용 할 수있는 사례를 접할 때마다 자신의 두뇌를 사용해야합니다.
Jason Williams

14

일반적으로 중복 코드가 많을 때 삼항 연산자를 선택합니다.

if (a > 0)
    answer = compute(a, b, c, d, e);
else
    answer = compute(-a, b, c, d, e);

삼항 연산자를 사용하면 다음과 같이 수행 할 수 있습니다.

answer = compute(a > 0 ? a : -a, b, c, d, e); 

12
개인적으로 나는 할 것이다 aVal = a > 0 ? a : -a; answer = compute(aVal,b,c,d,e);특히 경우 b, c, de도 치료가 필요합니다.
corsiKa

10
이 예제에서 왜 조건문을 사용합니까? Abs (a)를 얻고 compute ()를 한 번만 호출하면됩니다.
애쉬

2
그래, 나는 최고의 예를 만들지 않았다. :)
Ryan Bright

초보자에게는 동등하게 보이지 않습니다. 대답 = compute (a> 0? a, b, c, d, e : -a, b, c, d, e); ?
pbreitenbach 2010 년

@pbreitenbach : 아니요-우선 순위의 문제입니다.의 첫 번째 인수는 compute(...)이며 a > 0 ? a : -1, 모두 쉼표로 구분 된 다른 인수와 별도로 평가됩니다. 어쨌든, 불행히도 C ++에는 쉼표로 구분 된 값의 "튜플"을 처리하기 위해 질문하는 표기법이 없기 때문에 a > 0 ? (a, b, c, d, e) : (-a, b, c, d, e)불법적이며 compute자체 변경없이 작동하는 유사한 것은 없습니다 .
Tony Delroy 2013

12

변수가 정의 된 경우 요청에서 전송 된 값으로 설정하고 그렇지 않은 경우 일부 기본값으로 설정하려는 경우 웹 개발을 수행 할 때 특히 유용합니다.


3
웹 개발자의 +1 기본값은 삼항 연산자를 사용하기에 좋은 좋은 예입니다
Byron Whitlock

11

정말 멋진 사용법은 다음과 같습니다.

x = foo ? 1 :
    bar ? 2 :
    baz ? 3 :
          4;

10
PHP에서 이것에주의하십시오. 삼항 연산자는 PHP에서 잘못된 방식으로 연관됩니다. 기본적 foo으로 거짓이면 다른 테스트를 수행하지 않고 모든 것이 4로 평가됩니다.
Tom Busby 2015 년

4
@TomBusby — 와우. 이미 PHP를 싫어하는 사람이라면 PHP를 싫어하는 또 다른 이유입니다.
Todd Lehman

6

조건부 연산자는 다음과 같은 짧은 조건에 적합합니다.

varA = boolB ? valC : valD;

그런 식으로 작성하는 데 시간이 덜 걸리기 때문에 가끔 사용합니다. 안타깝게도 다른 개발자가 코드를 검색하면이 분기를 놓칠 수 있습니다. 또한 코드는 일반적으로 짧지 않으므로 일반적으로? 및 : 다음과 같이 별도의 줄에 :

doSomeStuffToSomething(shouldSomethingBeDone()
    ? getTheThingThatNeedsStuffDone()
    : getTheOtherThingThatNeedsStuffDone());

그러나 if / else 블록을 사용하는 것의 큰 장점 (그리고 내가 선호하는 이유)은 나중에 들어 와서 분기에 로직을 추가하는 것이 더 쉽다는 것입니다.

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else {
doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

또는 다른 조건을 추가하십시오.

if (shouldSomethingBeDone()) {
    doSomeStuffToSomething(getTheThingThatNeedsStuffDone());
    doSomeAdditionalStuff();
} else if (shouldThisOtherThingBeDone()){
    doSomeStuffToSomething(getTheOtherThingThatNeedsStuffDone());
}

그래서 결국, 그것은 당신을위한 편의 (사용하는 것이 더 짧습니다 :?)와 나중에 당신 (그리고 다른 사람들)을위한 편의에 관한 것입니다. 이것은 판결입니다 ...하지만 다른 모든 코드 서식 문제와 마찬가지로, 유일한 실제 규칙은 일관성을 유지하고 코드를 유지 (또는 등급 지정!)해야하는 사람들에게 시각적으로 예의를 갖추는 것입니다.

(모든 코드는 눈으로 컴파일 됨)


5

삼항 연산자를 사용할 때 인식해야 할 한 가지는 문이 아닌 표현식이라는 것입니다.

체계와 같은 기능적 언어에서는 구별이 존재하지 않습니다.

((> ab) ab 인 경우)

조건부? : 연산자 "if / else 구문만큼 유연하지 않은 것 같습니다."

기능적 언어에서는 그렇습니다.

명령형 언어로 프로그래밍 할 때 일반적으로 식 (할당, 조건문 등)을 사용하는 상황에서 삼항 연산자를 적용합니다.


5

위의 답변이 유효하고 가독성이 중요하다는 데 동의하지만 고려해야 할 두 가지 추가 사항이 있습니다.

  1. C # 6에서는 식 본문 메서드를 사용할 수 있습니다.

따라서 삼항을 사용하는 것이 특히 간결합니다.

string GetDrink(DayOfWeek day) 
   => day == DayOfWeek.Friday
      ? "Beer" : "Tea";
  1. 암시 적 형식 변환과 관련하여 동작이 다릅니다.

당신이 유형이있는 경우 T1T2그 양쪽 암시 적으로 변환 할 수 있습니다 T, 그 아래 수행 하지 작업 :

T GetT() => true ? new T1() : new T2();

(컴파일러 원계 식의 형태를 결정하려고 시도하고 있기 때문에간에 전환이없는 T1하고 T2).

반면에 if/else아래 버전은 작동합니다.

T GetT()
{
   if (true) return new T1();
   return new T2();
}

때문에이 T1변환되는 T등입니다T2


5

때로는 bool 값의 할당을 한눈에 읽기 쉽게 만들 수 있습니다.

// With
button.IsEnabled = someControl.HasError ? false : true;

// Without
button.IsEnabled = !someControl.HasError;

4

값을 설정할 때 항상 한 줄의 코드가된다는 것을 알고 있으면 일반적으로 삼항 (조건부) 연산자를 사용합니다. 내 코드와 논리가 앞으로 변경 될 가능성이 있다면 다른 프로그래머에게 더 명확하므로 if / else를 사용합니다.

당신에게 더 흥미로울 수 있습니다 ?? 연산자 .


4

조건부 연산자의 장점은 연산자라는 것입니다. 즉, 값을 반환합니다. if문 이므로 값을 반환 할 수 없습니다.


4

ternary (? :) 연산자의 사용을 간단한 한 줄 할당 if / else 논리로 제한하는 것이 좋습니다. 이 패턴과 유사한 것 :

if(<boolCondition>) {
    <variable> = <value>;
}
else {
    <variable> = <anotherValue>;
}

다음으로 쉽게 변환 할 수 있습니다.

<variable> = <boolCondition> ? <value> : <anotherValue>;

여러 줄을 평가하는 if / else if / else, 중첩 된 if / else 또는 if / else 분기 논리가 필요한 상황에서는 삼항 연산자를 사용하지 않습니다. 이러한 상황에서 삼항 연산자를 적용하면 코드를 읽을 수없고 혼란스럽고 관리 할 수 ​​없게됩니다. 도움이 되었기를 바랍니다.


2

?를 사용하면 성능상의 이점이 있습니다. 예를 들어 연산자. MS Visual C ++이지만 이것은 실제로 컴파일러에 특화된 것입니다. 컴파일러는 경우에 따라 실제로 조건 분기를 최적화 할 수 있습니다.


2

내가 가장 많이 사용하는 시나리오는 기본값, 특히 수익

return someIndex < maxIndex ? someIndex : maxIndex;

그것들은 정말 내가 좋은 곳이라고 생각하는 유일한 곳이지만, 그들에게는 내가합니다.

부울을 찾고 있다면 때로는 적절한 조치처럼 보일 수 있습니다.

bool hey = whatever < whatever_else ? true : false;

읽기와 이해가 너무 쉽기 때문에 그 아이디어는 항상 더 분명하게 던져 져야합니다.

bool hey = (whatever < whatever_else);

2

동일한 조건에서 여러 분기가 필요한 경우 if를 사용하십시오.

if (A == 6)
  f(1, 2, 3);
else
  f(4, 5, 6);

조건이 다른 여러 분기가 필요한 경우 문 개수가 눈덩이처럼 쌓이면 삼항을 사용하는 것이 좋습니다.

f( (A == 6)? 1: 4, (B == 6)? 2: 5, (C == 6)? 3: 6 );

또한 초기화에 삼항 연산자를 사용할 수 있습니다.

const int i = (A == 6)? 1 : 4;

if로하는 것은 매우 지저분합니다.

int i_temp;
if (A == 6)
   i_temp = 1;
else
   i_temp = 4;
const int i = i_temp;

범위를 변경하기 때문에 초기화를 if / else 안에 넣을 수 없습니다. 그러나 참조와 const 변수는 초기화시에만 바인딩 될 수 있습니다.


2

삼항 연산자는 rvalue 내에 포함될 수 있지만 if-then-else는 그렇지 않습니다. 반면에 if-then-else는 루프 및 기타 명령문을 실행할 수있는 반면 삼항 연산자는 rvalue 만 실행할 수 있습니다 (아마도 void).

관련 메모에서 && 및 || 연산자는 if-then-else로 구현하기 어려운 일부 실행 패턴을 허용합니다. 예를 들어, 호출 할 함수가 여러 개 있고 그중 하나라도 실패하면 코드 조각을 실행하려는 경우 && 연산자를 사용하여 멋지게 수행 할 수 있습니다. 해당 연산자없이 수행하려면 중복 코드, goto 또는 추가 플래그 변수가 필요합니다.


1

C # 7 , 새 사용할 수있는 심판 주민이 심판 호환 변수의 조건부 할당을 단순화 할 수 있습니다. 이제 다음과 같이 할 수 있습니다.

int i = 0;

T b = default(T), c = default(T);

// initialization of C#7 'ref-local' variable using a conditional r-value⁽¹⁾

ref T a = ref (i == 0 ? ref b : ref c);

... 또한 매우 훌륭합니다.

// assignment of l-value⁽²⁾ conditioned by C#7 'ref-locals'

(i == 0 ? ref b : ref c) = a;

코드의 라인의 값을 할당하는 a하나에 b또는 c값에 따라 i.



참고
1. r-value 는 할당 된 값인 할당 의 오른쪽 입니다.
2. l- 값 은 할당 된 값을받는 변수 인 할당 의 왼쪽 입니다.

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