Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
5: Understanding Editions in Rust
When I first started with Rust, I saw the term "Edition" and immediately panicked. Coming from the Python world, I assumed "Edition" was just a fancy word for "Breaking Version." I thought that if I started a project in the 2018 edition and a library I depended on was written in the 2015 edition, I was headed for a dependency hell that would require me to rewrite half my code. I've noticed a lot of you still have this same fear.
Editions are not "Breaking Versions" like Python 2 vs 3
In many languages, a major version bump means the old code simply won't run on the new runtime, or the new libraries won't work with the old compiler. Rust handles this differently. An "Edition" in Rust is not a change to the runtime or the binary format; it's essentially a change to the parser.
Think of it this way: the Rust compiler can speak multiple "dialects" of Rust simultaneously. When you tell Cargo which edition you're using in your Cargo.toml, you're just telling the compiler, "Hey, when you read my source files, use the rules for the 2021 dialect."
Here is a concrete example of why this matters. In the 2015 edition, async was not a reserved keyword. You could name a variable async if you really wanted to. In the 2018 edition, async became a keyword to support asynchronous programming. If Rust worked like other languages, every single library written in 2015 that used a variable named async would have broken the entire ecosystem the moment the 2018 edition dropped. But it didn't. The compiler simply reads those specific crates using the 2015 parser, and everything just works.
Your dependencies don't have to match your edition
This leads to the second big realization: your project's edition is local to your project. You don't need to coordinate with your dependencies. I've worked on projects where my top-level crate is Edition 2021, but I'm pulling in a deep dependency that hasn't been touched since 2015. The compiler doesn't care. It switches parsers on the fly as it moves from one crate to another.
You might be wondering, "Why bother with editions at all then? Why not just add new features forever?" Well, as a software engineer, I can tell you that language designers eventually hit a wall. They want to introduce a new keyword or change a behavior that would be a "breaking change" for existing code. Editions provide a way to evolve the language—introducing cleaner syntax or fixing old design mistakes—without forcing every developer on earth to migrate their code on the same day.
When you're looking at your Cargo.toml, you'll see a line like this:
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
If you change that to "2018" or "2015", you'll notice that some of your modern code suddenly starts throwing errors. You aren't breaking the program's logic; you're just telling the compiler to use an older, more restrictive dictionary to read your code.
📋 Practical Task
Upgrading a Legacy Cargo Project to Edition 2021
In this exercise, you will simulate a "legacy" project and experience how the edition setting affects the compiler's ability to parse keywords.
- Create a new Rust project using
cargo new edition_test. - Open
Cargo.tomland change theeditionfield from"2021"to"2015". - In
main.rs, try to define a variable namedasync(e.g.,let async = 10;) and print it. Runcargo run. You will see it works becauseasyncwas not a reserved keyword in 2015. - Now, keep that variable in your code, but go back to
Cargo.tomland change the edition back to"2021". - Run
cargo runagain. Observe the compiler error. The compiler is now using the 2021 parser, whereasyncis a reserved keyword for async/await blocks. - Fix the error by renaming the variable to
async_valand verify the project compiles.
There are no comments for now.