0Pricing
C# Academy · 강의

클로저와 캡처된 변수

지역 함수가 상태를 캡처하는 방식을 살펴봅니다.

클로저와 캡처된 변수은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

로컬 상태 캡처하기

로컬 함수(또는 람다)는 이를 포함하는 메서드의 변수를 읽고 수정할 수 있습니다. 이를 캡처라고 하며, 함수와 함수가 캡처한 변수는 함께 클로저를 구성합니다.

변수 캡처하기

로컬 함수는 이를 포함하는 메서드의 factor를 직접 사용합니다. 이를 매개 변수로 받는 것이 아니라 주변 범위에서 캡처합니다.

using System;

public class Program
{
    public static void Main()
    {
        int factor = 3;
        int Scale(int n) => n * factor; // captures factor

        Console.WriteLine(Scale(5));
        Console.WriteLine(Scale(10));
    }
}

캡처된 변수는 현재 상태를 참조합니다

클로저는 값의 스냅샷이 아니라 변수를 캡처합니다. 함수가 정의된 뒤 변수가 변경되면 함수는 새 값을 확인합니다.

using System;

public class Program
{
    public static void Main()
    {
        int offset = 10;
        int Add(int n) => n + offset;

        Console.WriteLine(Add(1)); // 11
        offset = 100;
        Console.WriteLine(Add(1)); // 101 - sees updated offset
    }
}

캡처된 변수 수정하기

클로저는 캡처된 변수에 값을 쓸 수 있으며, 변경 사항은 이를 포함하는 메서드에서도 확인할 수 있습니다. 따라서 클로저는 상태를 누적하는 데 유용합니다.

using System;

public class Program
{
    public static void Main()
    {
        int count = 0;
        void Tick() => count++;

        Tick(); Tick(); Tick();
        Console.WriteLine(count); // 3
    }
}

클로저 반환하기

로컬 변수를 캡처한 람다를 반환하면 해당 변수는 메서드보다 오래 유지됩니다. 캡처된 상태는 대리자가 유지되는 동안 계속 존재합니다.

using System;

public class Program
{
    static Func<int> MakeCounter()
    {
        int count = 0;
        return () => ++count; // captures count
    }

    public static void Main()
    {
        var next = MakeCounter();
        Console.WriteLine(next());
        Console.WriteLine(next());
        Console.WriteLine(next());
    }
}

독립적인 클로저

팩터리를 호출할 때마다 캡처된 변수의 새로운 집합이 만들어집니다. 이렇게 만든 두 카운터는 서로 영향을 주지 않습니다.

using System;

public class Program
{
    static Func<int> MakeCounter()
    {
        int count = 0;
        return () => ++count;
    }

    public static void Main()
    {
        var a = MakeCounter();
        var b = MakeCounter();
        Console.WriteLine(a()); // 1
        Console.WriteLine(a()); // 2
        Console.WriteLine(b()); // 1 - separate state
    }
}

foreach 캡처 수정 사항

최신 C#에서는 foreach 반복 변수에 반복마다 새로운 변수가 사용되므로 클로저가 예상한 값을 캡처합니다. 아래의 각 람다는 자체 항목을 기억합니다.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var actions = new List<Action>();
        foreach (var i in new[] { 1, 2, 3 })
            actions.Add(() => Console.WriteLine(i));

        foreach (var act in actions) act(); // prints 1, 2, 3
    }
}

for 반복문에서 캡처하기

전형적인 함정은 하나의 for 반복 변수가 모든 반복에서 공유된다는 점입니다. 따라서 모든 클로저가 최종 값을 확인합니다. 반복마다 사용하는 로컬 변수에 값을 복사하여 서로 다른 값을 캡처하십시오.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var actions = new List<Action>();
        for (int i = 0; i < 3; i++)
        {
            int copy = i; // fresh local each iteration
            actions.Add(() => Console.WriteLine(copy));
        }
        foreach (var act in actions) act(); // prints 0, 1, 2
    }
}

클로저는 값이 아닌 참조로 캡처합니다

캡처는 참조로 이루어지므로 캡처한 뒤 원본을 수정하면 클로저에서도 그 변경을 확인합니다. 읽기와 쓰기의 시점이 중요할 때 이 점을 기억하십시오.

using System;

public class Program
{
    public static void Main()
    {
        string message = "first";
        Action print = () => Console.WriteLine(message);

        print();          // first
        message = "second";
        print();          // second
    }
}

실용적인 사용: 구성 가능한 동작

클로저를 사용하면 컨텍스트가 미리 채워진 작은 함수를 만들 수 있습니다. 여기서는 할인 함수가 할인율을 캡처하여 재사용 가능한 구성된 계산기를 만듭니다.

using System;

public class Program
{
    static Func<double, double> MakeDiscount(double rate)
        => price => price * (1 - rate);

    public static void Main()
    {
        var tenOff = MakeDiscount(0.10);
        var halfOff = MakeDiscount(0.50);
        Console.WriteLine(tenOff(100));
        Console.WriteLine(halfOff(100));
    }
}

직접 해 보기

반환된 클로저가 private 상태를 계속 유지하는 카운터 팩터리를 만든 다음, 이를 사용하여 서로 독립적인 카운터 두 개를 만들어 보십시오.

using System;

public class Program
{
    static Func<int> MakeStepper(int step)
    {
        int current = 0;
        return () => { current += step; return current; }; // captures current and step
    }

    public static void Main()
    {
        var byTwos = MakeStepper(2);
        var byTens = MakeStepper(10);
        Console.WriteLine(byTwos()); // 2
        Console.WriteLine(byTwos()); // 4
        Console.WriteLine(byTens()); // 10 - separate state
    }
}

빠른 확인

캡처가 작동하는 방식을 추론해 보십시오.

복습

클로저는 이를 포함하는 변수를 참조로 캡처합니다.

  • 함수는 나중에 변경된 내용을 포함하여 변수의 현재 값을 확인합니다.
  • 캡처된 변수를 수정하여 메서드와 상태를 공유할 수 있습니다.
  • 반환된 클로저는 캡처한 변수를 계속 유지합니다.
  • for 반복문에서 서로 다른 값을 캡처하려면 반복마다 사용하는 로컬 변수를 두십시오.

자주 묻는 질문

“클로저와 캡처된 변수” 강의는 무료인가요?

네 — “클로저와 캡처된 변수” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“클로저와 캡처된 변수”에서 뭘 배우나요?

지역 함수가 상태를 캡처하는 방식을 살펴봅니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“클로저와 캡처된 변수” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 지역 함수 선언
  2. 클로저와 캡처된 변수
  3. 정적 지역 함수
  4. 지역 함수와 람다 비교
← C# Academy(으)로 돌아가기