본문으로 건너뛰기

안동민 개발노트

본문 시작

A - 키워드

Rust 2024의 엄격·예약·약한 키워드를 구분하고 원시 식별자와 에디션 마이그레이션을 정확히 적용합니다.

이 부록은 Rust 문법을 다시 가르치기보다, 컴파일 오류가 가리키는 단어를 Rust 2024 키워드 분류와 식별자 문맥으로 빠르게 되찾는 참조 색인입니다.

부록 A: 키워드

Rust 2024 키워드를 엄격, 예약, 약한 키워드로 나누고 각 분류의 식별자 사용 규칙과 전체 목록을 보여 주는 트리

Rust 2024 · tree

철자보다 문맥 강도를 먼저 분류한다

엄격 키워드와 예약 키워드는 일반 식별자가 될 수 없고, 약한 키워드는 정해진 문맥에서만 특별합니다. `_`와 `gen`, 그리고 'static을 서로 다른 가지에 두면 에디션과 문법 역할을 혼동하지 않습니다.

Rust 2024 키워드 세 분류 트리 Rust 2024 키워드라는 루트에서 엄격 키워드, 예약 키워드, 약한 키워드 세 가지로 분기한다. 엄격과 예약은 일반 식별자로 쓸 수 없고 약한 키워드는 정해진 문맥에서만 특별하다. Rust 2024 키워드 edition의 문법 분류 엄격 · strict 일반 식별자 불가 fn · match · async · _ 현재 문법에서 직접 사용 예약 · reserved 일반 식별자 불가 abstract · try · gen 미래 호환성을 위해 확보 약한 · weak 특정 문맥에서만 특별 'static · raw · safe macro_rules · union raw identifier는 네 번째 분류가 아니라 strict/reserved 충돌을 푸는 식별자 문법
Rust 2024 키워드 전체 목록
분류식별자 규칙키워드
strict일반 식별자 불가as async await break const continue crate dyn else enum extern false fn for if impl in let loop match mod move mut pub ref return Self self static struct super trait true type unsafe use where while _
reserved일반 식별자 불가abstract become box do final gen macro override priv try typeof unsized virtual yield
weak문맥별 특수 의미'static macro_rules raw safe union
Rust 2024 strict · reserved · weak
strict

일반 식별자 불가

as async await break const continue crate dyn else enum extern false fn for if impl in let loop match mod move mut pub ref return Self self static struct super trait true type unsafe use where while _

reserved

미래 호환성을 위해 예약

abstract become box do final gen macro override priv try typeof unsized virtual yield

weak

특정 문맥에서만 특별

'static macro_rules raw safe union

raw ID

분류가 아닌 충돌 해소 문법

strict 또는 reserved 키워드를 허용된 식별자 위치에서 쓸 때 r#name을 검토합니다.

static은 정적 아이템을 선언하는 strict 키워드이고, 'static은 라이프타임 문맥의 weak 키워드입니다.

Rust Reference는 키워드를 엄격 키워드(strict), 예약 키워드(reserved), **약한 키워드(weak)**로 구분합니다. 에디션은 Rust 컴파일러 버전과 별개인 소스 호환성 경계이며, 이 페이지는 Rust 2024를 기준으로 합니다.

엄격 키워드

엄격 키워드는 사용하는 에디션에서 일반 식별자로 쓸 수 없습니다. _도 이름 없는 패턴·자리표시자 등에 특별한 의미가 있는 엄격 키워드입니다.

as, async, await, break, const, continue, crate, dyn, else, enum, extern, false, fn, for, if, impl, in, let, loop, match, mod, move, mut, pub, ref, return, Self, self, static, struct, super, trait, true, type, unsafe, use, where, while, _

자주 혼동하는 몇 가지는 다음처럼 읽습니다.

  • async 함수와 블록은 Future를 만듭니다. .await는 그 Future가 준비되지 않았을 때 현재 비동기 작업이 실행자에게 제어를 양보할 수 있는 지점입니다. 이 문법만으로 동기 CPU 작업이 자동으로 비차단 작업이 되지는 않습니다.
  • const는 상수 아이템과 상수 문맥에 쓰이며, *const T에서는 해당 원시 포인터를 통해 pointee를 변경할 수 없음을 나타냅니다. “상수 원시 포인터”라는 별도 아이템을 선언하는 뜻은 아닙니다.
  • pub은 허용된 아이템·필드·연관 아이템·재노출의 가시성을 지정합니다. pub impl Type { ... }처럼 impl 블록 자체 앞에 붙이는 문법은 유효하지 않습니다.
  • static은 정적 아이템을 선언하는 엄격 키워드입니다. 프로그램 전체에 유효할 수 있는 라이프타임 이름 'static은 아래의 약한 키워드이며 둘은 같은 문법 범주가 아닙니다.

예약 키워드

예약 키워드는 현재 일반 문법 역할이 없더라도 향후 호환성을 위해 일반 식별자로 사용할 수 없습니다. Rust 2024에서 gen이 이 목록에 포함됩니다.

abstract, become, box, do, final, gen, macro, override, priv, try, typeof, unsized, virtual, yield

약한 키워드

약한 키워드는 특정 문맥에서만 특별한 의미를 갖습니다. 문맥 밖에서는 같은 철자가 식별자로 허용될 수 있으므로 엄격·예약 목록과 같은 방식으로 해석하면 안 됩니다.

'static, macro_rules, raw, safe, union

union은 union 아이템 선언에서, macro_rules는 선언형 매크로 문법에서 특별하게 해석됩니다. rawsafe도 Rust 2024의 정해진 문맥에서 약한 키워드로 동작합니다.

원시 식별자

다른 에디션이나 다른 언어에서 온 API가 키워드와 충돌할 때 r#name 문법으로 strict 또는 reserved 키워드를 식별자 위치에서 사용할 수 있습니다. 직접 소유한 이름이라면 장기적으로는 명확한 새 이름으로 바꾸는 편이 낫고, 원시 식별자는 주로 상호 운용성과 기존 공개 API 호출에 사용합니다.

키워드와 이름이 충돌했을 때 소유한 이름은 변경하고 외부 계약은 원시 식별자 가능 여부를 확인하며 금지된 다섯 표기를 제외하는 의사결정 흐름

Rust · raw identifier · flowchart

소유권과 허용 조건을 확인한 뒤 r#을 쓴다

내가 소유한 이름은 의미가 드러나게 바꾸고, 바꿀 수 없는 외부 또는 에디션 경계에서만 원시 식별자를 검토합니다. r#은 이름 내용이 아니며 모든 키워드에 적용되는 우회로도 아닙니다.

원시 식별자 사용 여부 결정 흐름 키워드 충돌을 발견하면 이름을 소유하는지 판단한다. 소유하면 이름을 바꾼다. 외부 계약이면 strict 또는 reserved인지, 금지된 다섯 표기인지 차례로 확인한 뒤 가능할 때 r#name을 사용하고 컴파일과 테스트로 검증한다. yes no no yes yes no 키워드 이름 충돌 expected identifier 내가 소유한 이름인가? 공개 계약 변경 가능? 명확한 이름으로 변경 호출부 갱신 · 컴파일 · 테스트 strict 또는 reserved? 식별자 위치의 충돌? 문맥과 문법을 재확인 weak 문맥 · 진단 후 종료 금지된 표기인가? _ crate self Self super 다른 API 경로 선택 r#로도 만들 수 없음 r#name 사용 정의·호출 컴파일과 테스트 컴파일 · 테스트 호출부와 공개 계약 확인
collision expected identifier
  1. 이름을 소유하는가?

    공개 계약까지 바꿀 수 있으면 새 이름으로 바꾸고 호출부 갱신, 컴파일, 테스트로 이 분기를 마칩니다.

  2. 외부 또는 에디션 계약인가?

    바꿀 수 없다면 strict 또는 reserved인지 확인합니다. weak라면 문맥과 다른 진단을 조사한 뒤 이 분기를 마칩니다.

  3. 금지된 다섯 표기를 제외한다

    r#_, r#crate, r#self, r#Self, r#super는 허용되지 않습니다.

  4. r#name으로 상호 운용

    r#try처럼 정의·호출을 컴파일하고 공개 API 테스트를 실행합니다.

identity

r#은 이름 내용이 아니다

r#foofoo는 서로 다른 두 식별자가 아닙니다.

에디션 이전에서는 현재 manifest 상태에서 cargo fix --edition을 실행해 수정안을 검토한 뒤 edition = "2024"를 직접 갱신하고 테스트합니다.

예를 들어 match를 그대로 함수 이름으로 쓰면 식별자가 와야 할 자리에 키워드가 나타났다는 진단을 받습니다.

src/main.rs
fn match(needle: &str, haystack: &str) -> bool {
    haystack.contains(needle)
}
error: expected identifier, found keyword `match`
 --> src/main.rs:1:4
  |
1 | fn match(needle: &str, haystack: &str) -> bool {
  |    ^^^^^ expected identifier, found keyword

외부 계약 때문에 이름을 유지해야 한다면 정의와 호출에서 원시 식별자를 사용합니다.

src/main.rs
fn r#match(needle: &str, haystack: &str) -> bool {
    haystack.contains(needle)
}

fn main() {
    assert!(r#match("foo", "foobar"));
}

r#는 식별자 내용에 포함되지 않는 문법 접두사입니다. 따라서 r#foofoo는 서로 다른 두 이름을 만드는 표기가 아닙니다.

엄격·예약 키워드라도 다음 다섯 표기는 허용되지 않습니다.

  • r#_
  • r#crate
  • r#self
  • r#Self
  • r#super

예를 들어 Rust 2015 라이브러리가 공개한 try 함수를 Rust 2018 이후 코드에서 호출해야 한다면 r#try()로 적을 수 있습니다. 여기서 차이는 “Rust 버전”이 아니라 크레이트가 선택한 에디션입니다.

에디션 마이그레이션

소유한 크레이트를 다음 에디션으로 옮길 때는 먼저 현재 에디션 상태에서 다음 명령을 실행합니다.

cargo fix --edition

이 명령은 에디션 호환 lint를 바탕으로 소스를 수정하지만 Cargo.tomledition 값은 바꾸지 않습니다. 변경을 검토하고 테스트한 뒤 manifest를 명시적으로 갱신합니다.

Cargo.toml
[package]
edition = "2024"

마지막으로 전체 테스트와 공개 API 호출부를 확인합니다. 소유한 심볼은 의미가 드러나는 이름으로 변경하고, 이름을 바꿀 수 없는 외부·생성 코드 경계에만 원시 식별자를 남기면 에디션 차이와 상호 운용 목적이 분명해집니다.