본문 바로가기

A - 키워드

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

이 부록은 러스트 문법을 다시 가르치기보다, 컴파일 오류가 가리키는 단어가 어떤 종류의 키워드인지 빠르게 찾아보는 참고 자료입니다. 목록은 Rust 2024 에디션의 Rust Reference 키워드 목록을 따릅니다.

부록 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 키워드입니다.

엄격 키워드와 예약 키워드는 일반 식별자로 쓸 수 없고, 약한 키워드는 정해진 문맥에서만 특별한 뜻을 가집니다. 그림처럼 _는 엄격 키워드, gen은 Rust 2024에서 예약 키워드, 'static은 약한 키워드로 서로 다른 갈래에 있다는 점을 기억해 두면, 에디션과 문법의 역할을 헷갈리지 않습니다. 원시 식별자는 네 번째 분류가 아니라, 엄격 키워드나 예약 키워드와 이름이 겹칠 때 쓰는 식별자 문법입니다.

엄격 키워드

다음 키워드는 지금 문법에서 쓰이며, 각각 설명한 기능을 가집니다.

키워드쓰임
_패턴에서 무엇이든 맞추되 바인딩하지 않는 와일드카드, 추론할 타입의 자리 표시
as기본 타입의 캐스팅, 아이템이 들어 있는 특정 트레이트의 지정, use 문에서 아이템의 이름 바꾸기
async현재 스레드를 막는 대신 Future를 돌려주기
awaitFuture의 결과가 준비될 때까지 실행을 멈추기
break루프를 곧바로 빠져나가기
const상수 아이템이나 상수 원시 포인터 정의하기
continue루프의 다음 반복으로 넘어가기
crate모듈 경로에서 크레이트 루트를 가리키기
dyn트레이트 객체로의 동적 디스패치
elseif와 if let 제어 흐름의 대안
enum열거형 정의하기
extern외부 함수나 변수 연결하기
false불리언 거짓 리터럴
fn함수나 함수 포인터 타입 정의하기
for반복자의 항목을 돌기, 트레이트 구현하기, 고차 라이프타임 지정하기
if조건 표현식의 결과에 따라 분기하기
impl고유 기능이나 트레이트 기능 구현하기
infor 루프 문법의 일부
let변수 바인딩하기
loop조건 없이 반복하기
match값을 패턴에 맞추기
mod모듈 정의하기
move클로저가 캡처한 것의 소유권을 모두 가져가게 하기
mut참조, 원시 포인터, 패턴 바인딩의 가변성 나타내기
pub구조체 필드, impl 블록, 모듈의 공개 범위 나타내기
ref참조로 바인딩하기
return함수에서 돌아가기
Self정의하거나 구현하고 있는 타입의 별칭
self메서드의 대상이나 현재 모듈
static전역 변수나 프로그램 실행 내내 이어지는 라이프타임
struct구조체 정의하기
super현재 모듈의 부모 모듈
trait트레이트 정의하기
true불리언 참 리터럴
type타입 별칭이나 연관 타입 정의하기
unsafe안전하지 않은 코드, 함수, 트레이트, 구현 나타내기
use심볼을 스코프로 가져오기
where타입을 제약하는 절 나타내기
while표현식의 결과에 따라 조건부로 반복하기

async, await, dyn은 2018 에디션에서 키워드가 되었습니다.

예약 키워드

다음 키워드는 아직 기능이 없지만, 앞으로 쓸 가능성이 있어 러스트가 예약해 둔 것입니다. 엄격 키워드와 같은 제약을 받습니다.

예약 키워드
abstract, become, box, do, final, gen, macro, override, priv, try, typeof, unsized, virtual, yield

try는 2018 에디션에서, gen은 2024 에디션에서 예약 키워드가 되었습니다.

약한 키워드

다음 키워드는 특정 문맥에서만 특별한 뜻을 가지며, 그 밖의 곳에서는 일반 식별자로 쓸 수 있습니다.

키워드특별한 뜻을 가지는 문맥
'static프로그램 실행 내내 이어지는 라이프타임
macro_rules선언적 매크로 정의
raw&raw const, &raw mut 같은 원시 대여 연산자
safeunsafe extern 블록 안에서 unsafe 없이 부를 수 있는 함수나 읽을 수 있는 정적 변수 표시
union유니온 선언에 쓰일 때만 키워드

원시 식별자

원시 식별자(raw identifier)는 보통은 키워드를 쓸 수 없는 곳에서 키워드를 쓰게 해 주는 문법입니다. 키워드 앞에 r#을 붙여 씁니다. 아래 그림은 이름이 키워드와 겹칠 때 무엇을 먼저 확인할지 보여 줍니다.

Rust 원시 식별자 선택 흐름

expected identifier 진단에서 소유한 이름이면 변경하고 외부 계약이면 strict/reserved 및 금지 표기를 확인해 r#name으로 수정·컴파일·테스트하는 작업 절차다. match 충돌 한 사례로 실제 수정 전후 식별자를 추적할 수 있다.

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

Rust · raw identifier · flowchart

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

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

원시 식별자 사용 여부 결정 흐름 키워드 충돌을 발견하면 이름을 소유하는지 판단한다. 소유하면 이름을 바꾼다. 외부 계약이면 strict 또는 reserved인지, 금지된 다섯 표기인지 차례로 확인한 뒤 가능할 때 r#name을 사용하고 컴파일과 테스트로 검증한다. yes no no yes yes no 키워드 이름 충돌 expected identifier 내가 소유한 이름인가? 공개 계약 변경 가능? 명확한 이름으로 변경 호출부 갱신 · 컴파일 · 테스트 strict 또는 reserved? 식별자 위치의 충돌? 문맥과 문법을 재확인 weak 문맥 · 진단 후 종료 금지된 표기인가? 아래의 5개 확인 다른 API 경로 선택 r#로도 만들 수 없음 r#name 사용 정의·호출 컴파일과 테스트 컴파일 · 테스트 호출부와 공개 계약 확인
식별자 충돌에서 이름 변경과 raw identifier 적용 가능성을 분기하고 예약 금지 이름은 별도 오류 경로로 남긴다.collision→rename: 계약부터 확인。rename→newname: 직접 이름 변경。rename→raw: 외부 이름 유지가 필요。raw→forbidden: raw 가능성 검사。raw→context: weak/context는 사용하는 위치를 별도 진단。forbidden→use: 허용되는 raw identifier。forbidden→other: 5개 금지 철자예아니오예약어그 밖아니오예식별자 충돌식별자 충돌외부 이름 · 에디션 확인이름을 바꿀 수 있나?이름을 바꿀 수 있나?내 코드 · 공개 계약 검사가능: 다른 이름가능:다른이름컴파일 ·테스트변경 불가: raw 검사변경불가: raw검사예약어?weak·contextweak ·context사용위치진단r# 금지?r# 금지?crate ·self ·Self ·super · _r#name 사용r#name사용같은식별자유지금지: API 이름 조정금지: API이름조정raw로해결불가
단계별 조건과 보충 설명
collision expected identifier
  1. 이름을 소유하는가?

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

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

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

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

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

  4. r#name으로 상호 운용

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

허용되지 않는 원시 식별자

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

r#은 이름 내용이 아니다

r#foo와 foo는 서로 다른 두 이름이 아닙니다.

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

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
이름 충돌

match를 식별자로 쓰려는 진단을 확인한다.

  • 입력: fn match
  • 진단: expected identifier
  • 키워드 위치와 이름의 소유권을 같이 확인한다.
수정 방식

소유한 이름은 변경하고, 외부 계약은 raw 가능 여부를 본다.

  • 소유한 이름: 명확한 새 이름
  • 외부 match: r#match 검토
  • 금지 표기와 문맥을 확인하지 않고 모든 토큰에 r#을 붙이지 않는다.
컴파일·테스트

정의와 호출을 함께 갱신해 확인한다.

  • 경계: 정의와 호출부
  • 근거: compiler·test
  • 한 위치 수정만으로 공개 계약 호환성까지 보장하지 않는다.

Rust 원시 식별자 선택 흐름

expected identifier 진단에서 소유한 이름이면 변경하고 외부 계약이면 strict/reserved 및 금지 표기를 확인해 r#name으로 수정·컴파일·테스트하는 작업 절차다. match 충돌 한 사례로 실제 수정 전후 식별자를 추적할 수 있다.

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

Rust · raw identifier · flowchart

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

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

원시 식별자 사용 여부 결정 흐름 키워드 충돌을 발견하면 이름을 소유하는지 판단한다. 소유하면 이름을 바꾼다. 외부 계약이면 strict 또는 reserved인지, 금지된 다섯 표기인지 차례로 확인한 뒤 가능할 때 r#name을 사용하고 컴파일과 테스트로 검증한다. yes no no yes yes no 키워드 이름 충돌 expected identifier 내가 소유한 이름인가? 공개 계약 변경 가능? 명확한 이름으로 변경 호출부 갱신 · 컴파일 · 테스트 strict 또는 reserved? 식별자 위치의 충돌? 문맥과 문법을 재확인 weak 문맥 · 진단 후 종료 금지된 표기인가? 아래의 5개 확인 다른 API 경로 선택 r#로도 만들 수 없음 r#name 사용 정의·호출 컴파일과 테스트 컴파일 · 테스트 호출부와 공개 계약 확인
식별자 충돌에서 이름 변경과 raw identifier 적용 가능성을 분기하고 예약 금지 이름은 별도 오류 경로로 남긴다.collision→rename: 계약부터 확인。rename→newname: 직접 이름 변경。rename→raw: 외부 이름 유지가 필요。raw→forbidden: raw 가능성 검사。raw→context: weak/context는 사용하는 위치를 별도 진단。forbidden→use: 허용되는 raw identifier。forbidden→other: 5개 금지 철자예아니오예약어그 밖아니오예식별자 충돌식별자 충돌외부 이름 · 에디션 확인이름을 바꿀 수 있나?이름을 바꿀 수 있나?내 코드 · 공개 계약 검사가능: 다른 이름가능:다른이름컴파일 ·테스트변경 불가: raw 검사변경불가: raw검사예약어?weak·contextweak ·context사용위치진단r# 금지?r# 금지?crate ·self ·Self ·super · _r#name 사용r#name사용같은식별자유지금지: API 이름 조정금지: API이름조정raw로해결불가
단계별 조건과 보충 설명
collision expected identifier
  1. 이름을 소유하는가?

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

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

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

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

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

  4. r#name으로 상호 운용

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

허용되지 않는 원시 식별자

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

r#은 이름 내용이 아니다

r#foo와 foo는 서로 다른 두 이름이 아닙니다.

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

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
이름 충돌

match를 식별자로 쓰려는 진단을 확인한다.

  • 입력: fn match
  • 진단: expected identifier
  • 키워드 위치와 이름의 소유권을 같이 확인한다.
수정 방식

소유한 이름은 변경하고, 외부 계약은 raw 가능 여부를 본다.

  • 소유한 이름: 명확한 새 이름
  • 외부 match: r#match 검토
  • 금지 표기와 문맥을 확인하지 않고 모든 토큰에 r#을 붙이지 않는다.
컴파일·테스트

정의와 호출을 함께 갱신해 확인한다.

  • 경계: 정의와 호출부
  • 근거: compiler·test
  • 한 위치 수정만으로 공개 계약 호환성까지 보장하지 않는다.

키워드와 이름이 겹쳐 expected identifier 진단을 받으면, 먼저 그 이름을 내가 정할 수 있는지 봅니다. 공개된 이름까지 바꿀 수 있다면, 뜻이 드러나는 새 이름으로 바꾸고 호출하는 곳을 고친 뒤 컴파일과 테스트로 확인합니다. 바꿀 수 없는 외부 이름이나 에디션의 문제라면, 그 단어가 엄격 키워드나 예약 키워드인지 확인합니다. 약한 키워드라면 쓰는 위치의 문맥과 다른 진단을 다시 봅니다. 다음으로 r#_, r#crate, r#self, r#Self, r#super 다섯 표기는 원시 식별자로도 만들 수 없으므로, 그런 경우에는 다른 API 경로를 고릅니다. 그 밖의 경우에는 r#name을 쓰고, 정의와 호출을 함께 컴파일하고 테스트합니다.

예를 들어 match는 키워드입니다. 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
  |
help: escape `match` to use it as an identifier
  |
1 | fn r#match(needle: &str, haystack: &str) -> bool {
  |    ++

이 오류는 match 키워드를 함수의 식별자로 쓸 수 없다는 것을 보여 줍니다. 출력의 help 줄처럼 컴파일러도 이름 앞에 r#을 붙이라고 제안합니다. match를 함수 이름으로 쓰려면, 다음처럼 원시 식별자 문법을 써야 합니다.

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

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

이 코드는 오류 없이 컴파일됩니다. 함수의 정의에서도, main에서 함수를 부르는 곳에서도 이름 앞에 r#을 붙였다는 점을 보세요. r#은 이름의 내용이 아니라 문법의 접두사이므로, r#foo와 foo는 서로 다른 두 이름이 아니라 같은 이름입니다.

원시 식별자를 쓰면, 그 단어가 예약된 키워드이더라도 원하는 어떤 단어든 식별자로 고를 수 있습니다. 그래서 식별자 이름을 더 자유롭게 고를 수 있고, 그 단어가 키워드가 아닌 언어로 쓰인 프로그램과 함께 쓸 수도 있습니다. 또 원시 식별자로, 크레이트가 쓰는 것과 다른 러스트 에디션으로 쓰인 라이브러리를 쓸 수 있습니다. 예를 들어 try는 2015 에디션에서는 키워드가 아니지만, 2018, 2021, 2024 에디션에서는 키워드입니다. 2015 에디션으로 쓰인 라이브러리에 try 함수가 있고 그것에 기대고 있다면, 2018 에디션 이후의 코드에서 그 함수를 부르려면 r#try라는 원시 식별자 문법을 써야 합니다. 에디션에 대한 자세한 정보는 E - 에디션을 보세요.

에디션 마이그레이션

직접 관리하는 크레이트를 다음 에디션으로 옮길 때는, 먼저 지금의 에디션 상태에서 다음 명령을 실행합니다. --edition을 주면 코드를 지금 에디션에서도 컴파일되고 다음 에디션에서도 같은 뜻이 되도록 고치므로, Cargo.toml의 edition을 바꾸기 전에 실행해야 합니다.

cargo fix --edition

이 명령은 새 에디션에서 키워드가 되는 이름을 원시 식별자로 바꾸는 것 같은, 자동으로 고칠 수 있는 변경을 코드에 적용합니다. 그다음 Cargo.toml의 edition 값을 새 에디션으로 바꾸고, 다시 빌드하고 테스트해 남은 문제를 고칩니다. 자동으로 바꾼 r#name이 직접 관리하는 이름이라면, 나중에 뜻이 드러나는 다른 이름으로 바꾸는 것이 읽기에 더 좋습니다.

정리

  • 엄격 키워드는 지금 문법에서 쓰이며 식별자로 쓸 수 없고, _도 엄격 키워드입니다.
  • 예약 키워드는 아직 기능이 없지만 앞으로를 위해 막아 둔 것이며, Rust 2024에서는 gen이 더해졌습니다.
  • 약한 키워드 'static, macro_rules, raw, safe, union은 정해진 문맥에서만 특별합니다.
  • 엄격 키워드나 예약 키워드를 식별자로 써야 한다면 r#match처럼 원시 식별자를 쓰며, r#_, r#crate, r#self, r#Self, r#super는 만들 수 없습니다.
  • 다른 에디션의 라이브러리에 있는 try 같은 이름을 부를 때 원시 식별자가 쓸모 있으며, 에디션을 옮길 때는 cargo fix --edition을 먼저 실행합니다.

연습 문제

1. 식별자로 쓸 수 있을까

(가) let union = 3; (나) let gen = 1; (Rust 2024) (다) fn r#type() {} (라) let r#self = 0;은 각각 컴파일되나요?

해설 보기

(가)는 union이 유니온 선언에서만 특별한 약한 키워드이므로 변수 이름으로 쓸 수 있어 컴파일됩니다. (나)는 Rust 2024에서 gen이 예약 키워드이므로 컴파일되지 않으며, r#gen으로 써야 합니다. (다)는 엄격 키워드 type을 원시 식별자로 쓴 것이라 컴파일됩니다. (라)는 r#self가 만들 수 없는 다섯 표기 가운데 하나라 컴파일되지 않습니다.

2. 이름을 바꿀까, r#을 붙일까

내 크레이트 안에서만 쓰는 함수 match와, 다른 팀이 2015 에디션으로 배포한 라이브러리의 공개 함수 try를 Rust 2024 코드에서 써야 합니다. 각각 어떻게 하나요?

해설 보기

내 크레이트 안의 함수는 이름을 직접 정할 수 있으므로, matches_needle처럼 뜻이 드러나는 이름으로 바꾸고 호출하는 곳도 고치는 편이 좋습니다. 다른 팀의 공개 함수는 이름을 바꿀 수 없으므로, r#try()처럼 원시 식별자로 부릅니다. try는 예약 키워드이고 만들 수 없는 다섯 표기에 들지 않으므로 원시 식별자로 쓸 수 있습니다.

다음 부록 B - 연산자와 기호에서는 러스트의 연산자와 기호를 문맥별로 정리합니다.