You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-07-11 16:50:16 +02:00
Introduce 'Idiomatic Rust' module
This commit is contained in:
@ -429,6 +429,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Idiomatic Rust
|
||||||
|
|
||||||
|
- [Welcome](idiomatic/welcome.md)
|
||||||
|
- [Leveraging the Type System](idiomatic/leveraging-the-type-system.md)
|
||||||
|
- [Newtype Pattern](idiomatic/leveraging-the-type-system/newtype-pattern.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Final Words
|
# Final Words
|
||||||
|
|
||||||
- [Thanks!](thanks.md)
|
- [Thanks!](thanks.md)
|
||||||
|
47
src/idiomatic/leveraging-the-type-system.md
Normal file
47
src/idiomatic/leveraging-the-type-system.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
minutes: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Leveraging the Type System
|
||||||
|
|
||||||
|
Rust's type system is _expressive_.\
|
||||||
|
We can use types and traits to build abstractions that make our code harder to
|
||||||
|
misuse. In some cases, we can even go as far as enforcing correctness at
|
||||||
|
_compile-time_. Quite often, these abstractions have no runtime
|
||||||
|
overhead[^zero-cost].
|
||||||
|
|
||||||
|
The type system can also be used to model concepts and constraints from your
|
||||||
|
business domain. By designing our types carefully, we can improve the clarity
|
||||||
|
and maintainability of the entire codebase.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
Additional items speaker may mention:
|
||||||
|
|
||||||
|
- Rust's type system borrows a lot of ideas from functional programming
|
||||||
|
languages.\
|
||||||
|
For example, Rust's enums are known as "algebraic data types" in languages
|
||||||
|
like Haskell and OCaml. You can take inspiration from learning material geared
|
||||||
|
towards functional languages when looking for guidance on how to design with
|
||||||
|
types. ["Domain Modeling Made Functional"][1] is a great resource on the
|
||||||
|
topic, with examples written in F#.
|
||||||
|
|
||||||
|
- Despite its functional roots, functional design patterns don't translate as-is
|
||||||
|
to Rust. For instance, extensive use of higher-kinded functions and types can
|
||||||
|
result in code that is harder to read and maintain. Design patterns in Rust
|
||||||
|
must take into account (and leverage!) the granular control over mutability
|
||||||
|
that comes with its borrow-checker.
|
||||||
|
|
||||||
|
- The same caution should be applied to object-oriented design patterns. Rust
|
||||||
|
doesn't support inheritance, and object boundaries must be mindful of the
|
||||||
|
constraints introduced by the borrow-checker.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{{%segment outline}}
|
||||||
|
|
||||||
|
[1]: https://pragprog.com/titles/swdddf/domain-modeling-made-functional/
|
||||||
|
|
||||||
|
[^zero-cost]: They often referred to as "zero-cost abstractions", although the
|
||||||
|
label can be misleading: the impact on compile times and code complexity may
|
||||||
|
be significant.
|
49
src/idiomatic/leveraging-the-type-system/newtype-pattern.md
Normal file
49
src/idiomatic/leveraging-the-type-system/newtype-pattern.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
minutes: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
# Newtype Pattern
|
||||||
|
|
||||||
|
A _newtype_ is a wrapper around an existing type, often a primitive:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// A unique user identifier, implemented as a newtype around `u64`.
|
||||||
|
pub struct UserId(u64);
|
||||||
|
```
|
||||||
|
|
||||||
|
Unlike type aliases, newtypes aren't interchangeable with the wrapped type:
|
||||||
|
|
||||||
|
```rust,compile_fail
|
||||||
|
# pub struct UserId(u64);
|
||||||
|
fn double(n: u64) -> u64 {
|
||||||
|
n * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// This doesn't compile ❌
|
||||||
|
double(UserId(1));
|
||||||
|
```
|
||||||
|
|
||||||
|
The Rust compiler won't implicitly convert to (or from) the underlying type.\
|
||||||
|
It won't let you use methods or operators defined on the underlying type either:
|
||||||
|
|
||||||
|
```rust,compile_fail
|
||||||
|
# pub struct UserId(u64);
|
||||||
|
// This doesn't compile ❌
|
||||||
|
assert_ne!(UserId(1), UserId(2));
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
- Run the example to show students the error message from the compiler.
|
||||||
|
|
||||||
|
- Modify the example to use a typealias instead of a newtype, such as
|
||||||
|
`type MessageId = u64`. The modified example should compile, thus highlighting
|
||||||
|
the differences between the two approaches.
|
||||||
|
|
||||||
|
- Stress that newtypes, out of the box, have no behaviour attached to them. You
|
||||||
|
need to be intentional about which methods and operators you are willing to
|
||||||
|
forward from the underlying type. In our `UserId` example, it is reasonable to
|
||||||
|
allow comparisons between `UserId`s, but it wouldn't make sense to allow
|
||||||
|
arithmetic operations like addition or subtraction.
|
||||||
|
|
||||||
|
</details>
|
26
src/idiomatic/welcome.md
Normal file
26
src/idiomatic/welcome.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
course: Idiomatic Rust
|
||||||
|
session: Morning
|
||||||
|
target_minutes: 180
|
||||||
|
---
|
||||||
|
|
||||||
|
# Welcome to Idiomatic Rust
|
||||||
|
|
||||||
|
[Rust Fundamentals](../welcome-day-1.md) introduced Rust syntax and core
|
||||||
|
concepts. We now want to go one step further: how do you use Rust _effectively_
|
||||||
|
in your projects? What does _idiomatic_ Rust look like?
|
||||||
|
|
||||||
|
This course is opinionated: we will nudge you towards some patterns, and away
|
||||||
|
from others. Nonetheless, we do recognize that some projects may have different
|
||||||
|
needs. We always provide the necessary information to help you make informed
|
||||||
|
decisions within the context and constraints of your own projects.
|
||||||
|
|
||||||
|
> ⚠️ This course is under **active development**.
|
||||||
|
>
|
||||||
|
> The material may change frequently and there might be errors that have not yet
|
||||||
|
> been spotted. Nonetheless, we encourage you to browse through and provide
|
||||||
|
> early feedback!
|
||||||
|
|
||||||
|
## Schedule
|
||||||
|
|
||||||
|
{{%session outline}}
|
Reference in New Issue
Block a user