1. 개념 정리
| 캡처 (Capture) |
람다식이 외부의 변수(지역 변수, 매개변수 등)를 참조하거나 포획하는 행위 |
| 클로저 (Closure) |
위에서 캡처된 변수들을 어디까지 살아 있게 하느냐를 포함한 실행 환경. 즉, 람다 + 캡처된 상태를 포함하는 실행 단위 |
- 캡처는 무엇을 참조했는가
- 클로저는 그 참조를 어떻게 유지하면서 실행되는가에 대한 개념
2. 예제
poolingManager.RegisterPoolObject(skillData.Value.skillData.skillName,
new ObjectPool<Skill>
(
() => CreateSkill(key),
poolingManager.OnGet,
poolingManager.OnRelease,
poolingManager.OnDes,
maxSize: 1
));
- 유니티에서 제공하는 ObjectPool<T>은 생성자에서 매개변수가 없는 함수를 받아야 한다.
- 이럴때 () => CreateSkill(key) 형태의 람다를 사용하면,
- 매개 변수 key를 캡처하여 마치 매개변수가 없는 함수처럼 전달할 수 있다.
3. 정리
- CreateSkill(key)는 원래 매개변수를 가지는 메서드이다.
- 하지만 람다를 통해 외부 변수 key를 캡처하면, Func<Skill> 타입으로 전달 가능하다.
- 즉, () => CreateSkill(key)는 매개변수가 있는 함수처럼 보이지만, 내부적으로는 key를 참조하고 있다.
- 이처럼 람다가 외부 값을 캡처하면, 해당 값을 힙에 유지하는 클로저를 만든다.
4. 번외
- 이런 람다의 특성 때문에 for문 등 반복문에 람다식이 포함되면
- 반복 변수(i 등)를 캡처로 처리하게 되면 모든 람다가 마지막 값을 출력하게 된다.
for (int i = 0; i < 3; i++)
{
actions.Add(() => Console.WriteLine(i));
}
// 결과: 2, 2, 2
- 그래서 반복 변수를 따로 저장해서 사용해야 되는 것이다.
for (int i = 0; i < 3; i++)
{
int temp = i;
actions.Add(() => Console.WriteLine(temp));
}
// 결과: 0, 1, 2