for-loop에 선언 된 변수는 지역 변수입니까?


133

C #을 오랫동안 사용해 왔지만 다음을 깨달은 적이 없습니다.

 public static void Main()
 {
     for (int i = 0; i < 5; i++)
     {

     }

     int i = 4;  //cannot declare as 'i' is declared in child scope                
     int A = i;  //cannot assign as 'i' does not exist in this context
 }

그렇다면이 이름으로 변수를 선언 할 수 없다면 for 블록 외부에서 'i'값을 사용할 수없는 이유는 무엇입니까?

for-loop가 사용하는 반복자 변수는 해당 범위에서만 유효하다고 생각했습니다.


8
외부 블록 범위는 for 루프의 범위를 포함하기 때문에
V4Vendetta

3
한 가지 방법은 전 범위에 선언 된 모든 변수는 함수가 재 작성 될 수 있다는 것을 의미, 그 범위의 시작에서 선언 할 수 있다는 것입니다 (동적으로 입력 된 언어, 특히과이 필요한 일부 코드 스타일 가이드) 그것의 생각int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Keith

2
@ V4Vendetta : 다른 방법입니다. 내부 블록은 상위 블록에 대한 블랙 박스입니다.
Sebastian Mach

4
이것이 불가능한 기술적 인 이유를 제외하고, 왜 이것이 (또는 이것의 변형)해야 할 합리적인 일입니까?! 분명히 다른 목적으로 사용되므로 다른 이름을 지정하십시오.
Dave

나는 이것을 전혀 몰랐지 만 완전히 멍한 제한처럼 보입니다.
alan2here

답변:


119

for-loop 외부 및 for-loop 외부에서 동일한 이름의 변수를 정의 할 수없는 이유는 외부 범위의 변수가 내부 범위에서 유효하기 때문입니다. 이것이 허용된다면 for-loop 내에 두 개의 'i'변수가 있음을 의미합니다.

보다: MSDN 범위

구체적으로 특별히:

local-variable-declaration (8.5.1 절)에 선언 된 지역 변수의 범위는 선언이 발생하는 블록입니다.

for 문의 초기화에 대해 선언 된 지역 변수의 범위 (섹션 8.8.3)는 초기화 장치, for 조건, for-iterator 및 for 문의 포함 명령문입니다.

또한 지역 변수 선언 (C # 사양의 섹션 8.5.1)

구체적으로 특별히:

local-variable-declaration에 선언 된 로컬 변수의 범위는 선언이 발생하는 블록입니다. 로컬 변수의 로컬 변수 선언 앞에있는 텍스트 위치에서 로컬 변수를 참조하면 오류가 발생합니다. 지역 변수의 범위 내에서 다른 지역 변수 나 상수를 같은 이름으로 선언하는 것은 컴파일 타임 오류입니다.

(Emphasis mine.)

이는 ifor 루프 내부 의 범위가 for 루프 임을 의미합니다 . ifor-loop 외부의 범위 는 전체 주요 방법 for-loop입니다. 의미하는 것은 두 번 나타납니다i 는 위와 같이 유효하지 않은 루프 내부에 한다는 입니다.

허용되지 않는 이유 는 루프 내에서만 사용할 수 int A = i;있기 때문 int i입니다 for. 따라서 더 이상 외부에서 액세스 할 수 없습니다for 루프 .

보시다시피이 두 가지 문제는 범위를 벗어난 결과입니다. 첫 번째 문제 ( int i = 4;)는 루프 범위 i내 에서 두 개의 변수를 생성합니다 for. 이므로int A = i; 범위를 벗어난 변수에 액세스 할 수 있습니다.

대신 할 수있는 i것은 전체 메소드에 범위가 지정되어 선언 하고 메소드와 for 루프 범위 모두에서 사용하는 것입니다. 이렇게하면 규칙을 어 기지 않아도됩니다.

public static void Main()
{
    int i;

    for (i = 0; i < 5; i++)
    {

    }

    // 'i' is only declared in the method scope now, 
    // no longer in the child scope -> valid.
    i = 4;

    // 'i' is declared in the method's scope -> valid. 
    int A = i;
}

편집 :

물론 C # 컴파일러는이 코드가 상당히 유효하게 컴파일되도록 변경 될 수 있습니다. 결국 이것은 유효합니다 :

for (int i = 0; i < 5; i++)
{
    Console.WriteLine(i);
}

for (int i = 5; i > 0; i--)
{
    Console.WriteLine(i);
}

그러나 코드 가독성 및 유지 관리가 다음과 같은 코드를 작성할 수 있다면 실제로 도움이 될 것입니다.

public static void Main()
{
    int i = 4;

    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(i);
    }

    for (int i = 5; i > 0; i--)
    {
        Console.WriteLine(i);
    }

    Console.WriteLine(i);
}

여기서 실수의 가능성에 대해 생각해보십시오. 마지막으로 i0이나 4를 인쇄합니까? 이제 이것은 매우 작은 예입니다. 추적하기 쉽고 추적하기 쉽지만 외부 i이름을 다른 이름으로 선언 한 것보다 유지 관리가 쉽고 읽기 쉽습니다 .

NB :

C #의 범위 지정 규칙은 C ++ 의 범위 지정 규칙과 다릅니다 . C ++에서 변수는 선언 된 위치부터 블록 끝까지 범위 내에 있습니다. C ++에서 코드를 유효한 구조로 만듭니다.


이해가 i되지만 내부 변수 에 오류가 있어야한다고 생각합니다 . 그것은 더 분명해 보입니다.
George Duckett

그러나 범위는 명령과 {}입니까? 아니면 부모 {}을 의미합니까?
John V

2
for 문 다음에 'A'를 선언하면 나중에 선언되므로 for 루프에서 유효하지 않습니다. 그래서 같은 이름을 사용할 수없는 이유를 알 수 없습니다.
John V

9
아마도이 대답은 완전성을 위해 C # 범위 규칙 이이 경우 C ++의 규칙과 다르다는 것을 지적해야합니다 . C ++에서 변수는 변수가 선언 된 위치부터 블록 끝까지 만 적용됩니다 ( msdn.microsoft.com/en-us/library/b7kfh662(v=vs.80).aspx 참조 ).
AAT

2
Java는 C ++과 C # 사이의 중간 접근 방식을 취합니다. OP의 예는 Java에서는 유효하지만 외부 i정의가 for 루프 전에 이동 한 경우 내부 i정의는 유효하지 않은 것으로 표시됩니다.
니콜라 Musatti

29

J.Kommer의 대답은 정확 : 지역 변수가 선언 될 때까지 잠시, 그것은 불법 지역 변수 선언 공간이 겹치는 다른 지역 변수 선언 공간에 같은 이름의 지역이있다.

여기에 위반되는 추가 C # 규칙이 있습니다. 추가 규칙은 간단한 이름을 사용하여 서로 다른 두 개의 중첩 로컬 변수 선언 공간 내에서 두 개의 다른 엔티티를 참조하는 것은 불법입니다. 따라서 귀하의 모범은 불법 일뿐만 아니라 불법이기도합니다.

class C
{
    int x;
    void M()
    {
        int y = x;
        if(whatever)
        {
            int x = 123;

"y"라는 로컬 변수 선언 공간에서 "x"라는 간단한 이름이 사용되어 "this.x"와 로컬 "x"라는 두 가지 다른 의미를 갖습니다.

이러한 문제에 대한 자세한 분석은 http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ 를 참조하십시오 .


2
또한, 변경을 수행 할 때 예제 코드가 컴파일된다는 점에 흥미가 있습니다.int y = this.x;
Phil

4
@ 필 : 맞습니다. 단순한 이름this.x 이 아닙니다 .
Eric Lippert

13

i루프 후 메소드 내부 를 선언하고 사용 하는 방법이 있습니다.

static void Main()
{
    for (int i = 0; i < 5; i++)
    {

    }

    {
        int i = 4;
        int A = i;
    }
}

Java 로이 작업을 수행 할 수 있습니다 (C에서 유래 할 수는 없습니다). 물론 변수 이름 때문에 약간 지저분합니다.


예, 이것은 C / C ++에서 시작됩니다.
Branko Dimitrijevic의

1
나는 이것을 전에 몰랐다. 깔끔한 언어 기능!

@MathiasLykkegaardLorenzen yes
Chris S

7

루프 i 전에 선언 했다면 for루프 내에서 선언하는 것이 여전히 유효해야한다고 생각합니까?

아니요, 두 범위가 겹치기 때문입니다.

할 수없는 대해서는 int A=i;때문에, 물론 그것은 단순히입니다 i만이 존재 for루프가해야처럼.


7

J.Kommer의 답변 외에도 (+1 btw). NET 범위의 표준에는 다음이 있습니다.

블록 If 문과 같은 블록 구조 내에서 변수를 선언하면 해당 변수의 범위는 블록 끝까지 만됩니다. 수명은 절차가 끝날 때까지입니다.

프로 시저 프로 시저 내에서 If 문 외부에서 변수를 선언하면 범위는 End Sub 또는 End Function까지입니다. 변수의 수명은 절차가 끝날 때까지입니다.

따라서 for 루프 헤더 내에서 decalared int는 for 루프 블록 중에 만 범위에 속 하지만 수명은 Main()코드가 완료 될 때까지 지속됩니다 .


5

이것을 생각하는 가장 쉬운 방법은 I의 외부 선언을 루프 위로 옮기는 것입니다. 그때 분명 해져야합니다.

어느 쪽이든 같은 범위이므로 수행 할 수 없습니다.


4

또한 C #의 규칙은 프로그래밍에있어 많은 시간이 필요하지 않지만 코드를 깨끗하고 읽기 쉽게 유지해야합니다.

예를 들어, 루프 후에 정의하면 괜찮지 만 코드를 읽고 정의 행을 놓친 사람은 루프 변수와 관련이 있다고 생각할 수 있습니다.


2

Kommer의 답변은 기술적으로 정확합니다. 생생한 블라인드 스크린 은유로 그것을 말로 표현하겠습니다.

for-block 내에서 코드는 외부 코드를 볼 수 있지만 외부 블록의 코드는 내부 코드를 볼 수 없도록 for-block과 엔 클로징 외부 블록 사이에 한 가지 방식의 블라인드 화면이 있습니다.

외부 코드는 inside를 볼 수 없으므로 내부에서 선언 된 것은 사용할 수 없습니다. 그러나 for-block의 코드는 inside와 outside를 모두 볼 수 있으므로 두 곳에서 선언 된 변수는 이름으로 명확하게 사용될 수 없습니다.

그래서 당신은 그것을 보지 못하거나 C #!


0

이 경우 같은 방식으로 봐 를 선언 intA의 using블록 :

using (int i = 0) {
  // i is in scope here
}
// here, i is out of scope

그러나을 int구현하지 IDisposable않으므로이 작업을 수행 할 수 없습니다. 그러나 int변수가 개인 범위에 배치되는 방법을 시각화하는 데 도움이 될 수 있습니다 .

또 다른 방법은

if (true) {
  int i = 0;
  // i is in scope here
}
// here, i is out of scope

이것이 무슨 일이 일어나고 있는지 시각화하는 데 도움이되기를 바랍니다.

루프 int내부에서 from 을 선언 for하면 코드가 좋고 빡빡하게 유지 되므로이 기능이 정말 좋습니다.


WTF? NEG에 태그를 붙이려면 볼에 이유를 말하도록하십시오.
jp2code

downvoter using가 아니고 의미 론이 다소 다르지만 (비록 downvoted 된 이유) 와의 비교 는 괜찮습니다. 참고 if (true)중복됩니다. 그것을 제거하면 범위 블록이 있습니다.
Abel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.