A - 키워드
Rust 2024의 엄격·예약·약한 키워드를 구분하고 원시 식별자와 에디션 마이그레이션을 정확히 적용합니다.
이 부록은 러스트 문법을 다시 가르치기보다, 컴파일 오류가 가리키는 단어가 어떤 종류의 키워드인지 빠르게 찾아보는 참고 자료입니다. 목록은 Rust 2024 에디션의 Rust Reference 키워드 목록을 따릅니다.
부록 A: 키워드
다음 목록에는 러스트 언어가 지금 쓰고 있거나 앞으로 쓰려고 예약해 둔 키워드가 들어 있습니다. 그래서 이 키워드들은 식별자로 쓸 수 없습니다(뒤의 원시 식별자에서 이야기할 경우는 예외입니다). 식별자는 함수, 변수, 매개변수, 구조체 필드, 모듈, 크레이트, 상수, 매크로, 정적 값, 속성, 타입, 트레이트, 라이프타임의 이름입니다. 아래 그림은 키워드의 세 분류와 전체 목록을 보여 줍니다.
Rust 2024 · tree
철자보다 문맥 강도를 먼저 분류한다
엄격 키워드와 예약 키워드는 일반 식별자가 될 수 없고, 약한 키워드는 정해진 문맥에서만 특별합니다. `_`와 `gen`, 그리고 'static을 서로 다른 가지에 두면 에디션과 문법 역할을 혼동하지 않습니다.
| 분류 | 식별자 규칙 | 키워드 |
|---|---|---|
| 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 |
일반 식별자 불가
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 _
미래 호환성을 위해 예약
abstract become box do final gen macro override priv try typeof unsized virtual yield
특정 문맥에서만 특별
'static macro_rules raw safe union
분류가 아닌 충돌 해소 문법
strict 또는 reserved 키워드를 허용된 식별자 위치에서 쓸 때 r#name을 검토합니다.
static은 정적 아이템을 선언하는 strict 키워드이고, 'static은 라이프타임 문맥의 weak 키워드입니다.
엄격 키워드와 예약 키워드는 일반 식별자로 쓸 수 없고, 약한 키워드는 정해진 문맥에서만 특별한 뜻을 가집니다. 그림처럼 _는 엄격 키워드, gen은 Rust 2024에서 예약 키워드, 'static은 약한 키워드로 서로 다른 갈래에 있다는 점을 기억해 두면, 에디션과 문법의 역할을 헷갈리지 않습니다. 원시 식별자는 네 번째 분류가 아니라, 엄격 키워드나 예약 키워드와 이름이 겹칠 때 쓰는 식별자 문법입니다.
엄격 키워드
다음 키워드는 지금 문법에서 쓰이며, 각각 설명한 기능을 가집니다.
| 키워드 | 쓰임 |
|---|---|
_ | 패턴에서 무엇이든 맞추되 바인딩하지 않는 와일드카드, 추론할 타입의 자리 표시 |
as | 기본 타입의 캐스팅, 아이템이 들어 있는 특정 트레이트의 지정, use 문에서 아이템의 이름 바꾸기 |
async | 현재 스레드를 막는 대신 Future를 돌려주기 |
await | Future의 결과가 준비될 때까지 실행을 멈추기 |
break | 루프를 곧바로 빠져나가기 |
const | 상수 아이템이나 상수 원시 포인터 정의하기 |
continue | 루프의 다음 반복으로 넘어가기 |
crate | 모듈 경로에서 크레이트 루트를 가리키기 |
dyn | 트레이트 객체로의 동적 디스패치 |
else | if와 if let 제어 흐름의 대안 |
enum | 열거형 정의하기 |
extern | 외부 함수나 변수 연결하기 |
false | 불리언 거짓 리터럴 |
fn | 함수나 함수 포인터 타입 정의하기 |
for | 반복자의 항목을 돌기, 트레이트 구현하기, 고차 라이프타임 지정하기 |
if | 조건 표현식의 결과에 따라 분기하기 |
impl | 고유 기능이나 트레이트 기능 구현하기 |
in | for 루프 문법의 일부 |
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 같은 원시 대여 연산자 |
safe | unsafe extern 블록 안에서 unsafe 없이 부를 수 있는 함수나 읽을 수 있는 정적 변수 표시 |
union | 유니온 선언에 쓰일 때만 키워드 |
원시 식별자
원시 식별자(raw identifier)는 보통은 키워드를 쓸 수 없는 곳에서 키워드를 쓰게 해 주는 문법입니다. 키워드 앞에 r#을 붙여 씁니다. 아래 그림은 이름이 키워드와 겹칠 때 무엇을 먼저 확인할지 보여 줍니다.
Rust 원시 식별자 선택 흐름
expected identifier 진단에서 소유한 이름이면 변경하고 외부 계약이면 strict/reserved 및 금지 표기를 확인해 r#name으로 수정·컴파일·테스트하는 작업 절차다. match 충돌 한 사례로 실제 수정 전후 식별자를 추적할 수 있다.
Rust · raw identifier · flowchart
소유권과 허용 조건을 확인한 뒤 r#을 쓴다
내가 소유한 이름은 의미가 드러나게 바꾸고, 바꿀 수 없는 외부 또는 에디션 경계에서만 원시 식별자를 검토합니다. r#은 이름 내용이 아니며 모든 키워드에 적용되는 우회로도 아닙니다.
단계별 조건과 보충 설명
expected identifier
이름을 소유하는가?
공개 계약까지 바꿀 수 있으면 새 이름으로 바꾸고 호출부 갱신, 컴파일, 테스트로 이 분기를 마칩니다.
외부 또는 에디션 계약인가?
바꿀 수 없다면 strict 또는 reserved인지 확인합니다. weak라면 문맥과 다른 진단을 조사한 뒤 이 분기를 마칩니다.
금지된 다섯 표기를 제외한다
r#_,r#crate,r#self,r#Self,r#super는 허용되지 않습니다.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를 식별자로 쓰려는 진단을 확인한다. |
|
|
| 수정 방식 소유한 이름은 변경하고, 외부 계약은 raw 가능 여부를 본다. |
|
|
| 컴파일·테스트 정의와 호출을 함께 갱신해 확인한다. |
|
|
Rust 원시 식별자 선택 흐름
expected identifier 진단에서 소유한 이름이면 변경하고 외부 계약이면 strict/reserved 및 금지 표기를 확인해 r#name으로 수정·컴파일·테스트하는 작업 절차다. match 충돌 한 사례로 실제 수정 전후 식별자를 추적할 수 있다.
Rust · raw identifier · flowchart
소유권과 허용 조건을 확인한 뒤 r#을 쓴다
내가 소유한 이름은 의미가 드러나게 바꾸고, 바꿀 수 없는 외부 또는 에디션 경계에서만 원시 식별자를 검토합니다. r#은 이름 내용이 아니며 모든 키워드에 적용되는 우회로도 아닙니다.
단계별 조건과 보충 설명
expected identifier
이름을 소유하는가?
공개 계약까지 바꿀 수 있으면 새 이름으로 바꾸고 호출부 갱신, 컴파일, 테스트로 이 분기를 마칩니다.
외부 또는 에디션 계약인가?
바꿀 수 없다면 strict 또는 reserved인지 확인합니다. weak라면 문맥과 다른 진단을 조사한 뒤 이 분기를 마칩니다.
금지된 다섯 표기를 제외한다
r#_,r#crate,r#self,r#Self,r#super는 허용되지 않습니다.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를 식별자로 쓰려는 진단을 확인한다. |
|
|
| 수정 방식 소유한 이름은 변경하고, 외부 계약은 raw 가능 여부를 본다. |
|
|
| 컴파일·테스트 정의와 호출을 함께 갱신해 확인한다. |
|
|
키워드와 이름이 겹쳐 expected identifier 진단을 받으면, 먼저 그 이름을 내가 정할 수 있는지 봅니다. 공개된 이름까지 바꿀 수 있다면, 뜻이 드러나는 새 이름으로 바꾸고 호출하는 곳을 고친 뒤 컴파일과 테스트로 확인합니다. 바꿀 수 없는 외부 이름이나 에디션의 문제라면, 그 단어가 엄격 키워드나 예약 키워드인지 확인합니다. 약한 키워드라면 쓰는 위치의 문맥과 다른 진단을 다시 봅니다. 다음으로 r#_, r#crate, r#self, r#Self, r#super 다섯 표기는 원시 식별자로도 만들 수 없으므로, 그런 경우에는 다른 API 경로를 고릅니다. 그 밖의 경우에는 r#name을 쓰고, 정의와 호출을 함께 컴파일하고 테스트합니다.
예를 들어 match는 키워드입니다. match를 이름으로 쓰는 다음 함수를 컴파일하려 하면,
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를 함수 이름으로 쓰려면, 다음처럼 원시 식별자 문법을 써야 합니다.
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 - 연산자와 기호에서는 러스트의 연산자와 기호를 문맥별로 정리합니다.