Menu

Zero let 바인딩: let으로 값에 이름 붙이기

Zero에서 let이 어떻게 동작하는지 정리했습니다. 지역 바인딩 선언, 타입 추론과 명시적 어노테이션, 그리고 왜 Zero가 여러 키워드 대신 단일 바인딩 형태를 쓰는지 살펴봅니다.

이 페이지에는 실행 가능한 에디터가 있습니다 — 편집하고 실행하면 결과를 바로 볼 수 있습니다.

값에 이름을 붙이는 방법은 하나

Zero에서 값에 이름을 붙일 때는 let을 씁니다.

let answer = 42

이게 문법의 전부입니다. var도 없고, const도 없고, auto도 없어요. 단일 바인딩 키워드 덕분에 언어가 작게 유지되고, 에이전트와 사람 모두 한 번 익혀서 어디서나 똑같이 적용할 수 있습니다.

let은 현재 스코프에 지역 바인딩을 도입합니다. 이 줄 이후로 answer는 둘러싼 블록이 끝날 때까지 42를 가리킵니다.

타입 추론

컴파일러는 오른쪽 식에서 타입을 추론합니다. 리터럴 42는 기본 타입이 i32이므로 answeri32가 됩니다. "hello" 리터럴은 문자열이므로:

let greeting = "hello"

greeting을 문자열 값에 바인딩합니다. Pair<i32, u8>을 반환하는 함수를 호출했다면 바인딩의 타입은 Pair<i32, u8>입니다.

let pair = makePair(40, 2_u8)

모든 바인딩에 타입을 적지 않아도 되니, 코드가 가볍게 읽힙니다.

명시적 타입 어노테이션

타입을 문서화하고 싶거나 — 추론이 다른 타입을 고를 만한 상황에서 특정 타입을 강제하고 싶을 때는 — 콜론 뒤에 타입을 적습니다.

let count: u8 = 10
let pair:  Pair<i32, u8> = makePair(40, 2_u8)

리터럴이 여러 타입에 해당할 수 있을 때 어노테이션이 컴파일러에 힌트가 되기도 합니다. 리터럴 10i32, i64, u8 등 어느 것이든 될 수 있는데, 어노테이션이 그것을 못 박아 줍니다.

리터럴에 타입 접미사를 붙여 바인딩 어노테이션을 대체할 수도 있습니다.

let small = 10_u8   // 리터럴 접미사로 u8
let big   = 10_i64  // 리터럴 접미사로 i64

두 형태 모두 유효합니다. 호출 지점에서 의도가 더 분명한 쪽을 고르세요.

바인딩 실전 예시

추론과 명시적 형태를 모두 쓰는 예제입니다 — Run을 눌러 실행해 보세요.

point는 오른쪽이 구조체 리터럴이라 타입을 명시적으로 적었습니다. total은 추론입니다. sumi32를 반환한다고 선언되어 있으니 바인딩도 i32가 됩니다.

스코프와 섀도잉

let 바인딩은 선언된 줄부터 둘러싼 블록의 끝까지 유효합니다. 중첩된 블록은 새 스코프를 만듭니다.

pub fun main(world: World) -> Void raises {
    let value = 1
    if true {
        let value = 2   // 이 블록 안에서 바깥의 'value'를 가립니다
        // 여기서 value == 2
    }
    // if 바깥으로 나오면 value == 1
}

안쪽 value는 바깥 것을 변경하는 게 아닙니다. if 블록의 닫는 중괄호에서 스코프가 끝나는 별도의 바인딩이에요. Rust나 ML 계열 언어와 같은 모델입니다. 중간 단계마다 새 이름을 짓지 않고 값을 일련의 단계로 변환할 때 특히 흔히 쓰입니다.

let하지 않는

다른 언어에서는 가능했지만 Zero의 let이 의도적으로 포함하지 않는 것들입니다.

  • 타입만 선언하기. 초기화되지 않은 바인딩을 만드는 let x: i32; 형태는 없습니다. 바인딩은 선언 시점에 값이 있어야 합니다.
  • 패턴 디스트럭처링 (아직). let (a, b) = pair라고 쓸 수 있는 언어들이 있죠. Zero는 의도적으로 작게 만들어졌고, 현재는 평범한 이름 바인딩에 집중합니다. 디스트럭처링이 추가됐는지는 최신 문서를 확인하세요.
  • 수명에 따른 여러 키워드. 별도의 static, const, let mut도 없고, 블록 스코프 vs 함수 스코프 변형도 없습니다. 키워드는 하나뿐이에요.

JavaScript 배경이라면 const가 가장 가까운 비유입니다. 이름이 블록 안에서 값에 바인딩되고, 안쪽 스코프에서 섀도잉이 가능하죠. Rust 배경이라면 여기서의 let은 명시적 mut 키워드가 빠진 Rust의 let과 같은 역할을 합니다.

패턴: 값을 단계적으로 쌓아 올리기

이름이 붙은 일련의 중간 단계로 계산을 적고 싶을 때 바인딩이 빛을 발합니다. 사람이 읽기에도 좋고, 각 줄을 지역적으로 추론하는 에이전트에게도 좋습니다.

각 줄이 함수의 나머지가 활용할 새로운 사실 하나를 도입합니다. 컴파일러는 여전히 타이트한 코드를 만들어내며, 중간 값에 이름을 붙이는 데 런타임 비용은 없습니다.

다음 글: 원시 타입

let은 바인딩할 무언가가 없으면 별 의미가 없습니다. 다음 문서에서는 Zero의 원시 타입을 살펴봅니다. 가장 자주 만나게 될 정수 너비, 부동소수점, 문자열, VoidBool 같은 것들이죠.

자주 묻는 질문

Zero에서 변수는 어떻게 선언하나요?

let을 사용합니다. 타입을 추론하게 두려면 let 이름 = 값, 타입을 명시적으로 적으려면 let 이름: 타입 = 값 형태로 씁니다. 예를 들면 let answer = 42let answer: i32 = 42처럼요. 둘 다 현재 스코프에서 answer라는 이름을 값 42에 바인딩합니다.

Zero는 let 바인딩의 타입을 추론하나요?

네. let total = sum(point)라고 적었을 때 sumi32를 반환한다면, 바인딩의 타입은 i32로 추론됩니다. 타입을 문서화하거나 특정 타입을 강제하고 싶을 때는 여전히 명시적으로 어노테이션을 적을 수 있어요. 예: let count: u8 = 10.

Zero의 let 바인딩은 가변(mutable)인가요?

단순한 let은 자신의 스코프 안에서 사용할 지역 바인딩을 만듭니다. 1.0 이전 Zero에서 가변성 관련 문법은 아직 발전 중이에요. 언어가 명시적 효과와 예측 가능한 메모리를 강조하기 때문에, 바인딩을 통해 상태를 변경하는 동작은 시그니처에 그 사실을 드러내야 합니다. 자신의 툴체인 버전에서 정확한 가변성 문법은 최신 Zero 문서를 확인하세요.

Zero의 let과 const는 어떻게 다른가요?

Zero는 함수 본문 안에서 일반적인 지역 바인딩에 let을 씁니다. JavaScript의 let/const/var처럼 여러 바인딩 키워드를 노출하지 않아요. 표면적을 작게 유지하려는 의도적인 설계 선택입니다. 컴파일 시간 상수는 보통 별도 키워드가 아니라 타입 시스템이나 최상위 선언으로 표현됩니다.

Zero에서 let 바인딩을 재선언할 수 있나요?

바인딩은 자신을 감싸는 스코프 안에서만 유효합니다. 중첩된 스코프에서 같은 이름으로 새로운 let을 선언하면, 그건 별도의 바인딩이고 안쪽 스코프 동안만 바깥 바인딩을 가립니다(shadowing). 안쪽 스코프가 끝나면 바깥 바인딩은 영향을 받지 않습니다. Rust나 ML 계열 언어와 같은 모델이에요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기