조건에서 할당을 사용하는 이유는 무엇입니까?


80

많은 언어에서 할당은 조건에서 합법적입니다. 나는 그 이유를 결코 이해하지 못했습니다. 왜 다음과 같이 작성 하시겠습니까?

if (var1 = var2) {
  ...
}

대신에:

var1 = var2;
if (var1) {
  ...
}

이 질문이 정말 언어에 구애받지 않습니까? 이 영향을받는 언어는 무엇입니까? 나는 C와 C ++가 무엇인지 알고 있습니다.
Wolf

답변:


115

if 문보다 루프에 더 유용합니다.

while( var = GetNext() )
{
  ...do something with var 
}

그렇지 않으면 작성해야 할

var = GetNext();
while( var )
{
 ...do something
 var = GetNext();
}

14
동의하지만 다음과 같이 쓸 것입니다. while ((var = GetNext ())! = 0) {...} 두 번 생각하지 않고 부분적으로는 기본 컴파일 옵션을 사용하지 않으면 GCC가 불평하기 때문입니다.
Jonathan Leffler

1
진실. for 루프 선언을 지원하는 언어를 사용하고 있고 루프 외부에서 이미 var를 사용하고 있지 않다고 가정합니다.
Gerald

1
ANSI C와 같은 일부 언어에서는 범위 지정 규칙이이 접근 방식을 허용하지 않습니다. @KerrekSB
wirrbel

7
@wirrbel : 1989 년의 ANSI C를 의미합니까? 증기 기관과 천공 카드가있을 때처럼? 그럴 수도 있지만 관련이 있습니까?
Kerrek SB 2013 년

3
이 경고는 한동안 할당에 문제가 있기 때문이 아니라 실제로 비교하려고 할 때 할당을 수행하는 것이 일반적인 버그이기 때문입니다. 경고를 없애고 싶다면 @Jonathan Leffler가 제안한 것과 동일한 JS를 수행 할 수 있습니다. 개인적으로 나는 JavaScript 진실 규칙을 믿지 못하기 때문에 어쨌든 그렇게 할 것입니다. :) 유일한 방법 인 C # 및 Java와 같은 일부 언어에서도 언급되어야합니다.
Gerald

33

종종 오류 감지 등과 관련된 일련의 작업에서 가장 유용하다고 생각합니다.

if ((rc = first_check(arg1, arg2)) != 0)
{
    report error based on rc
}
else if ((rc = second_check(arg2, arg3)) != 0)
{
    report error based on new rc
}
else if ((rc = third_check(arg3, arg4)) != 0)
{
    report error based on new rc
}
else
{
    do what you really wanted to do
}

대안 (조건에서 할당을 사용하지 않음)은 다음과 같습니다.

rc = first_check(arg1, arg2);
if (rc != 0)
{
    report error based on rc
}
else
{
    rc = second_check(arg2, arg3);
    if (rc != 0)
    {
        report error based on new rc
    }
    else
    {
        rc = third_check(arg3, arg4);
        if (rc != 0)
        {
            report error based on new rc
        }
        else
        {
            do what you really wanted to do
        }
    }
}

장기간의 오류 검사를 사용하면 대안은 페이지의 RHS를 벗어날 수 있지만 조건부 할당 버전은 그렇게하지 않습니다.

오류 검사는 단순히 검사가 아닌 '작업'( first_action(),,) second_action()일 수도 있습니다 third_action(). 즉, 기능이 관리하는 프로세스의 단계를 확인할 수 있습니다. (대부분 내가 작업하는 코드에서 함수는 사전 조건 검사 줄이나 함수가 작동하는 데 필요한 메모리 할당 또는 유사한 줄을 따라 있습니다).


예, 실제로 과도한 중첩을 피하기 위해이 작업을 수행 한 다음 온라인에서 검색하여 일반적인 관행인지 확인했습니다. 결국 나는 실제로 다른 사건이 하나 밖에 없었기 때문에 반대하기로 결정했지만, 이것은 과제를 조건에 두는 합법적 인 이유처럼 보입니다.
Ibrahim

동료들은 그것을 싫어합니다! 나에게 적어도 대부분의 경우 거대한 나무 또는 많은 수익보다 훨씬 더 유지 관리가 가능합니다. 저는 함수에서 단일 리턴을 선호합니다 ...
Nathan

합리적인 예로, 동반자 블록은 패턴을 명확하고 자명하게 만듭니다. 그러나 블록 내 ( "의사") 코드는 약간보기 흉해 보이며 역 스타일 ( 정말로하고 싶은 작업 을 끝에 배치)은 그다지 좋지 않습니다.
Wolf

31

함수를 호출하는 경우 더 유용합니다.

if (n = foo())
{
    /* foo returned a non-zero value, do something with the return value */
} else {
    /* foo returned zero, do something else */
}

물론, n = foo (); 별도의 진술에서 if (n), 그러나 위의 내용은 상당히 읽기 쉬운 관용구라고 생각합니다.


3
나는 당신이 그것을 괄호로 묶어야한다고 생각한다. 그렇지 않으면 gcc는 다음과 같이 불평 할 것이다. } 다른 {// foo는이 일을, 영 / NULL을 반환 다른}
파비오 포지

23

작업 할 데이터 또는 오류를 나타내는 플래그 (또는 완료)를 반환하는 함수를 호출하는 경우 유용 할 수 있습니다.

다음과 같은 것 :

while ((c = getchar()) != EOF) {
    // process the character
}

// end of file reached...

개인적으로 나는 그다지 좋아하지 않는 관용구이지만 때로는 대안이 더 추악합니다.


13

GCC는 실수로 과제를 진실 값으로 사용하려고 시도하는 경우 (-Wall 사용) 감지하는 데 도움이 될 수 있습니다.

if ((n = foo())) {
   ...
}

즉, 추가 괄호를 사용하여 이것이 실제로 원하는 것임을 나타냅니다.


1
알아 둘만 한. 동료들도 같은 방식으로 읽었 으면합니다.
Wolf

1
나를? 맙소사, 나는 절대로 할당을 진리 값으로 사용하려고하지 않을 것입니다. 나는 GCC가 추천하는 것을 언급하고 있었다.
JesperE

GCC는 Fortran 을 컴파일 할 수도 있습니다 . 아마도 프로그래밍 언어에 대해 명시 적일까요?
Peter Mortensen

9

관용구는 문 while대신 루프를 작성할 때 더 유용 if합니다. 를 들어 if당신이 설명하는대로 문, 당신은 그것을 분리 할 수 있습니다. 그러나이 구조가 없으면 자신을 반복해야합니다.

c = getchar();
while (c != EOF) {
    // ...
    c = getchar();
}

또는 loop-and-a-half 구조를 사용하십시오.

while (true) {
    c = getchar();
    if (c == EOF) break;
    // ...
}

나는 일반적으로 루프 앤 하프 형식을 선호합니다.


1
A의 while루프를 사용하여 선호 :do { c = getchar(); ... } while (c != EOF);
스콧 S

그리고 for루프를 대신 사용할 수 있습니다 .-- for (char c = getchar(); c != EOF; c= getchar()) { /* do something with c */ }이것은 가장 간결하며 for항상 스타일 적으로 '루프'라고 말합니다. 작은 단점은 c두 번 반환하는 함수를 지정해야한다는 것 입니다.
Scott S

4

짧은 대답은 표현식 지향 프로그래밍 언어가 더 간결한 코드를 허용 한다는 것입니다 . 명령을 쿼리에서 분리 하도록 강요하지 않습니다 .


1
if (), while () 및 기타 유사한 명령문에서 할당없이 코딩을 시행하는 것은 끊임없는 싸움입니다. C / C ++는 특히 ++ 및-연산자를 추가 할 때 종종 버그로 판명되는 부작용으로 악명이 높습니다.
Alexis Wilke 2012 년

1
첫 번째 링크는 쓸모가 없습니다. C 또는 C ++는 그런 언어가 아닌 것 같습니다.
Wolf

3

예를 들어 PHP에서는 SQL 데이터베이스 결과를 반복하는 데 유용합니다.

while ($row = mysql_fetch_assoc($result)) {
    // Display row
}

이것은 다음보다 훨씬 나아 보입니다.

$row = mysql_fetch_assoc($result);
while ($row) {
    // Display row
    $row = mysql_fetch_assoc($result);
}

4
이것은 또한 $ row가 그 루프 너머에 있지 않기 때문에 더 빨리 가비지 콜렉션에 적합하다는 깔끔한 부작용이 있습니다 (어쨌든 GC를 수행하는 언어에서).
Darren Greaves

2

다른 이점은 gdb를 사용하는 동안 발생합니다. 다음 코드에서 오류 코드는 단일 단계를 수행했는지 알 수 없습니다.

while (checkstatus() != -1) {
    // process
}

차라리

while (true) {
    int error = checkstatus();
    if (error != -1)
        // process
    else
        //fail
}

이제 단일 단계에서 checkstatus ()에서 반환 오류 코드가 무엇인지 알 수 있습니다.


1
코드를 디버깅 할 때 일시적인 변경에 도움이 될 수 있다는 뜻입니까?
Wolf

0

선택 사항을 반환하는 함수 ( boost::optional또는 std::optionalC ++ 17)에서 매우 유용합니다 .

std::optional<int> maybe_int(); // function maybe returns an int

if (auto i = maybe_int()) {
    use_int(*i);
}

이것은 내 변수의 범위를 줄이고 코드를 더 간결하게 만들고 가독성을 방해하지 않습니다.

포인터와 동일 :

int* ptr_int();

if (int* i = ptr_int()) {
    use_int(*i);
}

그건 그렇고, 변수의 범위를 제한하려면 이니셜 라이저와 함께 if를 사용할 수 있습니다. :)
cigien

-3

그 이유는:

  1. 성능 향상 (가끔)

  2. 적은 코드 (항상)

방법이있다 : 예를 가지고 someMethod()와에 if조건 당신은 메서드의 반환 값이 있는지 여부를 확인하려면 null. 그렇지 않은 경우 반환 값을 다시 사용합니다.

If(null != someMethod()){
    String s = someMethod();
    ......
    //Use s
}

동일한 메서드를 두 번 호출하므로 성능이 저하됩니다. 대신 다음을 사용하십시오.

String s;
If(null != (s = someMethod())) {
    ......
    //Use s
}

이것이 무슨 언어 지? C # 또는 C ++ ( "If"의 대문자)로 컴파일되지 않습니다.
Peter Mortensen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.