E - 에디션
Rust 에디션이 언어 변화를 선택적으로 적용하면서 크레이트 간 호환성을 유지하는 방식과 마이그레이션 절차를 이해합니다.
러스트를 쓰다 보면 컴파일러의 버전과 크레이트의 에디션이 둘 다 "버전"처럼 보여 헷갈리기 쉽습니다. 둘은 서로 다른 것을 고릅니다. 아래 표는 툴체인의 버전과 크레이트의 에디션이 각각 무엇을 정하는지 나란히 비교한 것입니다.
Rust · edition · two-axis matrix
도구의 버전과 소스를 읽는 규칙은 따로 선택된다
toolchain을 올리는 일은 compiler 릴리스를 바꾸고, edition은 크레이트별 언어 호환성 모드를 고릅니다. edition은 parser 설정에 그치지 않고 이름·메서드 해석, closure capture, prelude 같은 동작과 Cargo resolver·rustfmt style 기본값에도 연결됩니다. 지원 범위 안에서는 서로 다른 edition 크레이트를 함께 링크할 수 있습니다.
| 개념 축 | 선택 위치와 현재 값 | 바꾸는 것 | 독립적으로 남는 것 |
|---|---|---|---|
toolchain · rustc 1.x | rustup, CI image 또는 rust-toolchain.toml로 compiler 릴리스를 선택 | 그 릴리스에 안정화된 기능과 진단, 수정, code generation과 target 지원을 사용 | Cargo.toml의 edition 값을 자동으로 바꾸지 않음. 해당 rustc 릴리스 전에 존재한 에디션을 지원 |
crate · edition | 각 package의 Cargo.toml에 2015 | 2018 | 2021 | 2024를 선언 | 키워드와 경로, prelude와 메서드 해석, closure capture와 drop 같은 언어와 표준 라이브러리 호환 동작을 선택 | 사용할 rustc 릴리스나 의존 크레이트의 edition을 고정하지 않음. 예: 배열 .into_iter() 해석은 2021부터 달라짐 |
| edition 연동 도구 | 최상위 2021/2024 package의 기본 Cargo resolver는 각각 2/3. cargo fmt는 package edition을 style 기본값으로 사용 | workspace 의존성 선택과 formatting 출력이 달라질 수 있음 | resolver는 workspace 전역이며 명시값이 기본값을 덮어씀. style_edition으로 formatting 전환을 따로 고정 가능 |
| 빌드 그래프의 결합 | Cargo가 각 크레이트에 알맞은 edition을 전달하고 최상위 workspace resolver로 같은 의존성 그래프를 조율 | 각 소스는 자신의 edition 규칙으로 compiler 내부 표현까지 번역됨 | 지원 에디션이 다른 크레이트도 링크·호출 가능. 전체 그래프의 edition을 한 번에 맞출 필요 없음 |
rustc 1.x · compiler 릴리스
rustup, CI image나 rust-toolchain.toml로 고릅니다. 안정 기능과 진단, codegen, target 지원이 달라지지만 manifest의 edition은 자동 변경되지 않습니다. Rust 2024 크레이트에는 rustc와 Cargo 1.85+가 필요합니다.
Cargo.toml edition · 크레이트 해석 규칙
package마다 2015, 2018, 2021, 2024 중 하나를 선언합니다. 구문뿐 아니라 이름과 메서드 해석, prelude, closure capture와 drop 같은 언어와 표준 라이브러리 동작을 고릅니다.
resolver와 formatting 기본값도 확인한다
최상위 2021/2024 package의 기본 resolver는 각각 2/3입니다. resolver는 workspace 전역이고 명시값이 우선합니다. cargo fmt는 package edition을 따르지만 style_edition으로 출력 전환을 분리할 수 있습니다.
지원되는 서로 다른 에디션은 함께 링크된다
Cargo가 각 크레이트의 edition을 compiler에 전달하고 최상위 workspace resolver로 그래프를 고릅니다. 각 소스는 자신의 규칙으로 번역되므로 전체 의존성 그래프를 같은 edition으로 동시에 옮길 필요가 없습니다.
현재 에디션 기준
Rust 에디션은 현재 2015·2018·2021·2024 네 가지입니다. Rust 2024는 Rust 1.85에서 안정화되었고, 공식 Rust Book의 현재 본문도 2024 edition을 사용합니다.
명시하지 않았을 때
기존 manifest에 edition 키가 없으면 역호환을 위해 2015가 적용됩니다. 현재 Cargo가 새로 만드는 프로젝트는 기본적으로 최신 안정 에디션인 2024를 선언합니다.
새 edition을 이해하지 못하는 오래된 compiler로 그 크레이트를 빌드할 수는 없습니다. 반대로 최신 toolchain만 쓴다고 기존 크레이트가 자동 전환되지는 않습니다. edition 전환 때는 resolver·Cargo.lock과 rustfmt style diff도 별도로 검증합니다.
툴체인은 rustup이나 CI 이미지, rust-toolchain.toml로 컴파일러의 릴리스를 고르며, 그 릴리스에서 안정화된 기능과 진단, 코드 생성, 지원하는 대상을 정합니다. 툴체인을 올려도 Cargo.toml의 edition 값은 바뀌지 않으며, 그 컴파일러 릴리스보다 먼저 나온 에디션을 지원합니다. 에디션은 각 패키지의 Cargo.toml에 2015, 2018, 2021, 2024 가운데 하나로 적으며, 키워드와 경로, 프렐류드와 메서드 해석, 클로저의 캡처와 값이 버려지는 방식 같은 언어와 표준 라이브러리의 호환 동작을 고릅니다. 예를 들어 배열의 .into_iter()를 해석하는 방식은 2021 에디션부터 달라졌습니다. 에디션은 Cargo의 해석기(resolver)와 rustfmt의 스타일 기본값에도 이어지며, 최상위 패키지가 2021이면 해석기 2, 2024이면 해석기 3이 기본입니다. 해석기는 작업공간 전체에 적용되며 명시한 값이 기본값보다 앞서고, rustfmt의 서식은 style_edition으로 따로 정할 수 있습니다. Cargo는 각 크레이트에 알맞은 에디션을 넘겨 컴파일하므로, 지원하는 범위 안에서는 에디션이 다른 크레이트들도 같은 의존성 그래프에서 서로 이어 쓸 수 있습니다.
부록 E - 에디션
1장에서 cargo new가 Cargo.toml 파일에 에디션에 관한 메타데이터를 조금 더한다는 것을 보았습니다. 이 부록에서는 그것이 무엇을 뜻하는지 이야기합니다.
러스트 언어와 컴파일러는 6주의 릴리스 주기를 가지므로, 사용자는 새 기능을 꾸준히 받습니다. 다른 프로그래밍 언어는 큰 변경을 드물게 릴리스하지만, 러스트는 작은 업데이트를 더 자주 릴리스합니다. 시간이 지나면 이 작은 변경들이 쌓입니다. 하지만 릴리스마다 돌아보며 "와, Rust 1.10과 Rust 1.31 사이에 러스트가 많이 바뀌었구나!"라고 말하기는 어려울 수 있습니다.
러스트 팀은 대략 3년마다 새 러스트 에디션(edition)을 만듭니다. 각 에디션은 이미 들어간 기능들을 문서와 도구까지 완전히 갖춘 하나의 분명한 묶음으로 모읍니다. 새 에디션은 평소의 6주 릴리스 과정의 일부로 나옵니다.
에디션은 사람들마다 서로 다른 목적을 가집니다.
| 사람 | 에디션이 주는 것 |
|---|---|
| 지금 러스트를 쓰는 사람 | 점진적인 변경들을 이해하기 쉬운 묶음으로 모아 줍니다. |
| 러스트를 쓰지 않는 사람 | 몇 가지 큰 발전이 이루어졌다는 신호가 되어, 러스트를 다시 살펴볼 계기가 될 수 있습니다. |
| 러스트를 개발하는 사람 | 프로젝트 전체가 모일 지점을 줍니다. |
이 글을 쓰는 시점에 쓸 수 있는 러스트 에디션은 Rust 2015, Rust 2018, Rust 2021, Rust 2024 네 가지입니다. 이 교재는 Rust 2024 에디션의 관용구로 쓰였습니다.
Cargo.toml의 edition 키는 컴파일러가 코드에 어느 에디션을 써야 하는지 나타냅니다. 이 키가 없으면 러스트는 하위 호환성 때문에 2015를 에디션 값으로 씁니다.
각 프로젝트는 기본인 2015 에디션이 아닌 다른 에디션을 고를 수 있습니다. 에디션에는 코드의 식별자와 충돌하는 새 키워드를 도입하는 것처럼, 호환되지 않는 변경이 들어 있을 수 있습니다. 하지만 그런 변경을 고르지 않는 한, 쓰는 러스트 컴파일러의 버전을 올려도 코드는 계속 컴파일될 것입니다.
모든 러스트 컴파일러는 그 컴파일러가 릴리스되기 전에 있던 모든 에디션을 지원하며, 지원하는 어떤 에디션의 크레이트든 함께 링크할 수 있습니다. 컴파일러는 크레이트마다 그 크레이트의 에디션 규칙으로 소스를 해석하지만, 어느 에디션으로 쓴 코드든 컴파일러 안에서는 결국 같은 내부 표현으로 바뀝니다. 그러므로 Rust 2015를 쓰고 있고 의존성 하나가 Rust 2018을 쓰더라도, 프로젝트는 컴파일되고 그 의존성을 쓸 수 있습니다. 반대로 프로젝트가 Rust 2018을 쓰고 의존성이 Rust 2015를 쓰는 상황도 동작합니다.
분명히 하자면, 대부분의 기능은 모든 에디션에서 쓸 수 있습니다. 어느 러스트 에디션을 쓰는 개발자든, 새 안정 릴리스가 나오면 계속 개선을 볼 것입니다. 하지만 어떤 경우에는, 주로 새 키워드가 더해질 때, 일부 새 기능은 나중의 에디션에서만 쓸 수 있습니다. 그런 기능을 쓰고 싶다면 에디션을 바꿔야 합니다.
자세한 내용은 Rust Edition Guide를 보세요. 에디션 사이의 차이를 모두 나열하고, cargo fix로 코드를 새 에디션으로 자동으로 고치는 방법을 설명하는 완전한 책입니다.
에디션 마이그레이션
컴파일러를 올리는 일과 에디션을 바꾸는 일은 한 번의 변경에 섞지 않는 것이 좋습니다. 아래 그림은 두 일을 나누어 진행하는 흐름을 보여 줍니다.
Rust 컴파일러 업데이트와 에디션 마이그레이션 흐름
기준선 기록 뒤 toolchain-only와 edition migration을 분리하고 fix→manifest/resolver/lockfile/style 검토→지원 구성 build/test/CI→기준선 반영을 수행하는 작업 절차다. 두 대안을 한 diff로 연결하지 않고 2024의 1.85+ 및 자동 수정 한계를 유지한다.
Rust · edition migration · flowchart
compiler 업데이트와 edition 전환을 한 diff로 섞지 않는다
현재 기준선을 기록한 뒤 toolchain-only와 edition migration 경로를 분기합니다. Rust 2024 경로는 rustc·Cargo 1.85+를 전제로 source fix, manifest·resolver·lockfile·style diff를 나누어 검토합니다. 두 경로 모두 검증을 통과한 뒤에만 팀 기준으로 승격합니다.
현재 기준선 기록
rustc --version, crate별 edition·rust-version, workspace resolver, lockfile, rustfmt style, CI target·feature와 테스트 결과를 남깁니다.
어느 축을 바꾸는가?
아래 두 경로를 같은 diff에 섞지 않습니다. 왼쪽은 compiler release만, 오른쪽은 crate의 edition과 연동 도구 기본값까지 바꿉니다.
edition을 유지한다
toolchain과 CI image만 올려 compiler 진단, codegen, target 지원 변화를 격리합니다. crate edition, resolver와 style 기준은 그대로 둡니다.
Rust 1.85+에서 단계별 전환
① 의존성 갱신을 별도 diff로 검토합니다. ② package·feature·target별 cargo fix --edition과 수동 검토를 거칩니다. ③ edition = "2024", workspace resolver, Cargo.lock과 format diff를 각각 확인합니다.
빌드·테스트·CI 검증
두 경로 모두 target과 feature 조합, mixed-edition 의존성을 실행 검증합니다. edition 경로는 resolver 재해결과 Cargo.lock, cargo tree, rustfmt style 차이도 따로 확인합니다.
팀 기준선에 반영
검증된 edition·resolver·style, MSRV 또는 toolchain pin, CI image와 전환 이유를 문서화합니다.
자동 수정 범위
cargo fix --edition은 기본적으로 선택된 package의 모든 Cargo target을 검사합니다. 다만 활성 feature와 현재 target platform의 cfg에서 보이는 코드만 수정하므로, 필요하면 --all-features와 다른 --target으로 반복합니다.
작업 단위
toolchain 업데이트, 의존성 갱신, 자동 수정, manifest·resolver·lockfile 변경과 포맷 diff를 분리하면 회귀 원인을 추적하기 쉽습니다.
의존성 에디션
의존 크레이트를 같은 edition으로 강제 이동할 필요는 없습니다. 선택한 rustc가 각 크레이트의 edition을 지원하고 전체 API와 동작 검증을 통과하면 함께 링크할 수 있습니다.
공식 Edition Guide의 기본 순서는 의존성 갱신, cargo fix --edition, manifest edition 변경, build·test, format입니다. Rust 2024에는 rustc·Cargo 1.85 이상이 필요하며 resolver 3 전환은 자동 migration 대상이 아닙니다. 자동 도구가 의미 보존을 보장하지 않으므로 source·lockfile·format diff와 실제 지원 구성을 팀 검증 절차에 포함합니다.
이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
| 범위 | 원문 |
|---|---|
| 관계·조건 설명 | 기준선을 기록하고 compiler만 바꾸는 경로와 edition 2024로 전환하는 경로를 나누어 진행한다. edition 경로는 자동 수정과 manifest resolver lockfile style 검토를 거친다. 두 경로는 전체 구성을 검증하고 팀 기준선에 반영한다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 기준선 기록 compiler·edition·resolver·lockfile·style을 분리한다. |
|
|
| 2024 수정·검토 B 사례의 fix와 manifest·resolver·style 차이를 본다. |
|
|
| 지원 구성 검증 target/feature와 mixed edition의 build·test·CI를 확인한다. |
|
|
Rust 컴파일러 업데이트와 에디션 마이그레이션 흐름
기준선 기록 뒤 toolchain-only와 edition migration을 분리하고 fix→manifest/resolver/lockfile/style 검토→지원 구성 build/test/CI→기준선 반영을 수행하는 작업 절차다. 두 대안을 한 diff로 연결하지 않고 2024의 1.85+ 및 자동 수정 한계를 유지한다.
Rust · edition migration · flowchart
compiler 업데이트와 edition 전환을 한 diff로 섞지 않는다
현재 기준선을 기록한 뒤 toolchain-only와 edition migration 경로를 분기합니다. Rust 2024 경로는 rustc·Cargo 1.85+를 전제로 source fix, manifest·resolver·lockfile·style diff를 나누어 검토합니다. 두 경로 모두 검증을 통과한 뒤에만 팀 기준으로 승격합니다.
현재 기준선 기록
rustc --version, crate별 edition·rust-version, workspace resolver, lockfile, rustfmt style, CI target·feature와 테스트 결과를 남깁니다.
어느 축을 바꾸는가?
아래 두 경로를 같은 diff에 섞지 않습니다. 왼쪽은 compiler release만, 오른쪽은 crate의 edition과 연동 도구 기본값까지 바꿉니다.
edition을 유지한다
toolchain과 CI image만 올려 compiler 진단, codegen, target 지원 변화를 격리합니다. crate edition, resolver와 style 기준은 그대로 둡니다.
Rust 1.85+에서 단계별 전환
① 의존성 갱신을 별도 diff로 검토합니다. ② package·feature·target별 cargo fix --edition과 수동 검토를 거칩니다. ③ edition = "2024", workspace resolver, Cargo.lock과 format diff를 각각 확인합니다.
빌드·테스트·CI 검증
두 경로 모두 target과 feature 조합, mixed-edition 의존성을 실행 검증합니다. edition 경로는 resolver 재해결과 Cargo.lock, cargo tree, rustfmt style 차이도 따로 확인합니다.
팀 기준선에 반영
검증된 edition·resolver·style, MSRV 또는 toolchain pin, CI image와 전환 이유를 문서화합니다.
자동 수정 범위
cargo fix --edition은 기본적으로 선택된 package의 모든 Cargo target을 검사합니다. 다만 활성 feature와 현재 target platform의 cfg에서 보이는 코드만 수정하므로, 필요하면 --all-features와 다른 --target으로 반복합니다.
작업 단위
toolchain 업데이트, 의존성 갱신, 자동 수정, manifest·resolver·lockfile 변경과 포맷 diff를 분리하면 회귀 원인을 추적하기 쉽습니다.
의존성 에디션
의존 크레이트를 같은 edition으로 강제 이동할 필요는 없습니다. 선택한 rustc가 각 크레이트의 edition을 지원하고 전체 API와 동작 검증을 통과하면 함께 링크할 수 있습니다.
공식 Edition Guide의 기본 순서는 의존성 갱신, cargo fix --edition, manifest edition 변경, build·test, format입니다. Rust 2024에는 rustc·Cargo 1.85 이상이 필요하며 resolver 3 전환은 자동 migration 대상이 아닙니다. 자동 도구가 의미 보존을 보장하지 않으므로 source·lockfile·format diff와 실제 지원 구성을 팀 검증 절차에 포함합니다.
이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
| 범위 | 원문 |
|---|---|
| 관계·조건 설명 | 기준선을 기록하고 compiler만 바꾸는 경로와 edition 2024로 전환하는 경로를 나누어 진행한다. edition 경로는 자동 수정과 manifest resolver lockfile style 검토를 거친다. 두 경로는 전체 구성을 검증하고 팀 기준선에 반영한다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 기준선 기록 compiler·edition·resolver·lockfile·style을 분리한다. |
|
|
| 2024 수정·검토 B 사례의 fix와 manifest·resolver·style 차이를 본다. |
|
|
| 지원 구성 검증 target/feature와 mixed edition의 build·test·CI를 확인한다. |
|
|
먼저 지금의 기준을 기록합니다. rustc --version, 크레이트별 edition과 rust-version, 작업공간의 해석기, Cargo.lock, rustfmt의 스타일, CI의 대상과 기능, 테스트 결과를 남겨 둡니다. 그다음 어느 축을 바꿀지 정합니다. 컴파일러만 올리는 경로에서는 툴체인과 CI 이미지만 바꾸고, 크레이트의 에디션과 해석기, 스타일은 그대로 두어 컴파일러의 진단, 코드 생성, 대상 지원의 변화만 따로 봅니다. Rust 2024로 옮기는 경로는 rustc와 Cargo 1.85 이상을 전제로 합니다. 의존성 갱신은 따로 검토하고, 패키지, 기능, 대상마다 cargo fix --edition을 실행해 결과를 직접 확인한 뒤, Cargo.toml의 edition과 해석기, Cargo.lock, 매크로, 문서 테스트, 포맷의 차이를 나누어 검토합니다. 두 경로 모두 대상과 기능, 에디션이 섞인 구성까지 빌드하고 테스트하고 CI로 검증한 뒤에야 팀의 기준으로 삼습니다.
에디션을 옮기는 명령은 다음과 같습니다. 이 명령은 지금의 에디션에서 실행해, 다음 에디션에서 바뀌는 부분을 고칩니다.
cargo fix --editioncargo fix --edition은 Cargo.toml의 edition 값을 바꾸지 않으므로, 고친 코드를 확인한 뒤 edition = "2024"처럼 직접 바꾸고 다시 빌드하고 테스트합니다. 선택적인 기능이나 플랫폼별 코드가 있다면 --all-features와 필요한 --target을 조합해 따로 실행합니다. 이 명령은 활성화한 기능과 지금 플랫폼의 cfg에 들어간 코드만 고치기 때문입니다.
정리
- 툴체인의 버전은 컴파일러 릴리스를, 크레이트의 에디션은 그 크레이트의 소스를 해석하는 규칙을 고르며, 둘은 따로 정합니다.
- 러스트는 대략 3년마다 에디션을 내며, 지금은 2015, 2018, 2021, 2024가 있고,
Cargo.toml에edition이 없으면 2015로 봅니다. - 컴파일러는 자신보다 먼저 나온 모든 에디션을 지원하며, 에디션이 다른 크레이트들도 함께 링크해 쓸 수 있습니다.
- 에디션에는 새 키워드 같은 호환되지 않는 변경이 들어 있을 수 있지만, 고르지 않는 한 컴파일러를 올려도 코드는 계속 컴파일됩니다.
- 에디션을 옮길 때는 기준을 기록하고,
cargo fix --edition을 실행한 뒤edition값을 직접 바꾸고, 해석기와 포맷의 차이까지 검증합니다.
연습 문제
1. 무엇이 바뀔까
Cargo.toml에 edition = "2021"인 프로젝트에서 (가) rustup으로 컴파일러를 1.80에서 1.99로 올렸다. (나) edition을 "2024"로 바꿨다. 각각의 경우 gen을 변수 이름으로 쓰는 코드는 어떻게 되나요?
해설 보기
(가)는 컴파일러만 올린 것이므로 에디션은 여전히 2021이고, 2021에서 gen은 키워드가 아니므로 코드는 그대로 컴파일됩니다. (나)는 에디션을 2024로 바꾼 것이며, 2024에서 gen은 예약 키워드이므로 컴파일되지 않습니다. 에디션을 바꾸기 전에 cargo fix --edition을 실행하면 이 이름을 r#gen으로 고쳐 줍니다.
2. 섞어 쓸 수 있을까
내 프로젝트는 Rust 2024 에디션이고, 의존하는 크레이트 하나는 Rust 2018 에디션입니다. 그 크레이트를 쓰려면 그 크레이트도 2024로 옮겨야 하나요?
해설 보기
옮기지 않아도 됩니다. Cargo는 각 크레이트를 자기 에디션의 규칙으로 컴파일하므로, 2018 에디션의 크레이트와 2024 에디션의 프로젝트를 함께 링크해 쓸 수 있습니다. 다만 그 크레이트의 공개 API에 2024에서 키워드가 된 이름이 있다면, 내 코드에서는 r#gen()처럼 원시 식별자로 불러야 합니다.
다음 부록 F - 추가 학습 자료에서는 이 교재 다음에 볼 만한 공식 문서와 자료를 정리합니다.