Navigation
Search
|
4 key concepts for Rust beginners
Wednesday December 18, 2024. 10:00 AM , from InfoWorld
Few languages are as highly esteemed by developers as Rust, which promises robust memory safety without compromising speed. Rust also has a steep learning curve, though, and some of its programming concepts can feel like a barrier to knowing it well.
As an aid to the aspiring Rustaceans, here are four key concepts of the Rustosphere—the kinds of things a more experienced Rust developer might wish they knew from the beginning. Having a grasp on these concepts will give you a head start when you start writing programs with Rust. Also see: Rust tutorial: Get started with the Rust language. All Rust variables are immutable by default Rust’s first assumption about any variable you create is that it is immutable by default. If you say let x=1;, the variable x is bound to the value 1 for the lifetime of the program. Any variable that might change has to be specifically declared as such with the mut (for “mutable”) keyword; e.g., let mut x=1;. This “Sir, may I?” strategy is a deliberate design choice for Rust, even though at first it might seem ornery. But here’s the rationale: Immutable entities in a program are easier to reason about and make guarantees about—especially guarantees about memory safety, which is Rust’s big selling point. If the compiler knows some element in a given scope doesn’t change once it’s assigned, most of the memory management issues around that element evaporate. Another rationale for this design decision is that it forces the programmer to think about what actually does need to change in a program. Taking input from the user, for instance, or reading from a file, are operations that must be handled mutably. But you can leave many other operations as immutable with no loss of functionality. With advanced Rust data structures, such as reference-counted Cell objects, you can use immutability to your advantage. For example, this immutable singly-linked list has no mutable components; every change to the list essentially involves creating a new list, albeit one that doesn’t waste memory copying because the existing list data can be re-used. Rust has strict rules of ownership Rust’s memory management model relies on a strict concept of ownership. Any value in Rust can only be modified by one thing at a time—its owner. Think of how there’s only one baseball at a time in a baseball game, and only one player at a time handling it. That owner can change over the lifetime of a program, in the same way the ball is thrown between players. But Rust refuses to allow a value to have more than one owner at once, just as we’d rather not have baseball players tussling over the ball. Also see: Rust memory safety explained. It’s possible for something to be read by more than one thing at once in Rust, but not possible for something to be changed by more than one thing at once. There can be multiple shared references or “borrows” to something at once, for the sake of read-only access, but there can be only one exclusive (read-write) reference to something at once. The net effect is that Rust programmers must pay close attention to what data can be modified at what time. It’s important to understand that a program that breaks these rules won’t just crash; in Rust, it won’t even compile. That’s because the rules of ownership are not optional. (More on this later.) Another net effect is that Rust memory management at runtime is not handled by way of a dedicated garbage collection system, as with C# or Go. Things like dynamic reference counting are possible, but they’re more akin to C++’s smart pointers—albeit with better runtime controls for thread safety. A final note is that ownership does not make it impossible for Rust programs to have data race conditions. Data access across threads, for instance, still needs to be serialized with primitives like locks or queues to avoid unpredictable in-program behavior. But Rust does make it impossible for code to have many common memory-access-error bugs that plague other languages. Borrow checking enforces Rust’s ownership rules A big part of Rust’s appeal is that its ownership rules forbid representing states that might cause common memory errors. These problems aren’t caught at runtime but at compile time, so they never enter production. A downside is that Rust programmers spend a fair amount of time, at least when they’re first learning the language, figuring out how to appease the compiler. Program behaviors that might have passed unnoticed in other languages (and possibly caused memory errors at runtime) cause the Rust compiler to stop cold. The other big downside is that you can’t opt out of this behavior. You can’t toggle off Rust’s borrow-checking behavior the way you could, say, disable a code linter for another language. It makes for better software in the long run. But the immediate cost is a language that’s both slower to learn and slower to iterate in. Rust does allow you to fence off parts of your code with the unsafe keyword, and lift some restrictions, like the ability to dereference a raw pointer. But unsafe does not turn off borrow checking entirely, or anything like that. It’s for taking code with certain behaviors you don’t want casually used (again, like dereferencing a raw pointer) and “gating” it for safety. Also see: Safety off: Programming in Rust with ‘unsafe’. Rust editions support backward-compatibility It’s been almost a decade since Rust 1.0 came out, and the language has evolved aggressively since then. Many new features came along, not all of them backward-compatible with older versions of the language. To keep these changes from making it hard to maintain code in the long term, Rust introduced the concept of language editions. Editions, which are published roughly every three years, provide a guarantee of compatibility. By and large, features added to Rust are supported going forward. Breaking changes—ones that are backward-incompatible—are added to the next edition rather than the current one. Once you choose an edition, you’re not tied to it forever. You can migrate your code to future editions by way of both automated tooling and manual inspection. But there’s also a good chance the changes you are interested in will be backward-compatible with your older code, and thus available without migrating editions.
https://www.infoworld.com/article/3612162/4-key-concepts-for-rust-beginners.html
Related News |
25 sources
Current Date
Dec, Mon 23 - 21:05 CET
|