바인딩은 값에 이름을 부여하는 작업입니다. 선언 시점에 두 가지 요소가 결정됩니다. 하나는 해당 이름에 새 값을 재대입할 수 있는지 여부이고, 다른 하나는 코드 내에서 해당 이름이 참조되는 유효 범위입니다. 클로저는 외부 함수 실행이 끝난 후에도 필요한 바인딩을 유지할 수 있습니다.
캡처한 바인딩이 바뀌는 모습 보기
다음 코드를 bindings-scope-closures.tpz로 저장합니다.
function 카운터만들기(시작: int) -> () -> int {
let mut 현재 = 시작
() => {
현재 = 현재 + 1
현재
}
}
let 레이블 = "outer"
let 다음 = 카운터만들기(10)
{
let 레이블 = "inner"
print("{레이블}: {다음()}, {다음()}")
}
print(레이블)검사한 다음 실행합니다.
topaz check bindings-scope-closures.tpz
topaz run bindings-scope-closures.tpz두 번의 호출은 하나의 카운터를 공유합니다. 블록 내부의 레이블은 블록이 끝날 때 소멸합니다.
inner: 11, 12
outer복사된 값이 아니라 바인딩 따라가기
카운터만들기는 가변 바인딩 현재를 생성한 뒤 람다를 반환합니다. 람다는 현재를 사용하므로 이 바인딩을 캡처합니다. 원본 선언이 let mut이므로 람다 내부에서 새 값을 재대입할 수 있습니다.
클로저는 초기값 10을 복사해 두지 않고 단일 가변 저장 공간을 지속적으로 참조합니다. 이 저장 공간을 셀이라고 부릅니다. 첫 번째 호출은 셀 값을 11로 변경하고, 두 번째 호출은 그 값을 읽어 12로 변경합니다. 카운터만들기 실행이 끝난 후에도 다음이 이 셀을 참조하므로 셀은 유지됩니다.
레이블은 렉시컬 스코프를 보여 줍니다. 내부 블록은 외부 이름을 가리고 자체 바인딩을 생성할 수 있습니다. 블록 내부에서 레이블은 "inner"를 가리킵니다. 블록을 벗어나면 내부 바인딩의 스코프가 종료되어 외부의 "outer"가 다시 참조됩니다. 동일한 스코프에서 같은 이름을 두 번 선언하면 정적 오류가 발생합니다.
바인딩을 의도적으로 고르기
| 형태 | 사용할 때 | 재대입 |
|---|---|---|
const | 제한적 상수 표현식으로 계산되는 컴파일 시점 값 | 불가 |
let | 바인딩을 변경하지 않는 일반적인 런타임 값 | 불가 |
let mut | 재대입 자체가 모델의 일부인 상태 | 가능 |
기본 선택은 let입니다. 추후 대입하는 동작이 의미가 있을 때만 mut를 붙이세요. 그러면 어떤 상태가 변하는지 선언 위치에서 바로 파악할 수 있습니다.
매개변수와 패턴이 생성한 이름은 불변입니다. 함수 내부에서 변경되는 상태가 필요하면 매개변수 값을 새로운 let mut 바인딩에 담으세요. 그리고 그 상태를 잘 설명하는 이름을 붙이세요.
흔한 실수: 캡처를 스냅샷으로 생각하기
불변 바인딩을 캡처하면 클로저 내부에서도 읽기 전용입니다. 가변 바인딩을 캡처하면 유효한 셀을 그대로 공유합니다. 따라서 한 클로저가 변경한 값을 동일한 바인딩의 다음 읽기 작업에서 확인할 수 있습니다. 두 클로저가 하나의 가변 바인딩을 캡처하더라도 카운터가 따로 생성되지 않고 같은 셀을 공유합니다.
클로저를 생성하는 시점에도 스코프 규칙은 동일하게 적용됩니다. 해당 위치에서 참조할 수 있는 이름만 캡처 가능하며, 이후에 선언되는 이름이나 인접 블록 내부의 바인딩에는 접근할 수 없습니다.
정확한 한계
- 내부 스코프는 외부 이름을 가릴 수 있습니다. 다만 단일 스코프에서 동일한 이름을 두 번 선언할 수는 없습니다.
- 불변
let·const·매개변수·패턴 바인딩에는 새 값을 재대입할 수 없습니다. - 가변 선언에는 단일 식별자만 사용하며, 구조 분해 패턴은 사용할 수 없습니다.
- 명시적 캡처 목록, 이동 캡처 문법, Rust식 클로저 트레이트, 빌림 수신자 문법은 지원하지 않습니다.
- 리소스 수명 관리는 별도의 영역입니다. File 전용
using과 결정론적 정리는 Defer와 리소스에서 다룹니다.
불변 바인딩과 가변 바인딩을 처음 다루는 위치는 값과 함수입니다. 명명된 함수와 람다, 제네릭 함수 중 무엇을 선택할지는 함수와 제네릭에서 이어서 살펴보세요.