You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-26 10:41:01 +02:00
Format all Markdown files with dprint
(#1157)
This is the result of running `dprint fmt` after removing `src/` from the list of excluded directories. This also reformats the Rust code: we might want to tweak this a bit in the future since some of the changes removes the hand-formatting. Of course, this formatting can be seen as a mis-feature, so maybe this is good overall. Thanks to mdbook-i18n-helpers 0.2, the POT file is nearly unchanged after this, meaning that all existing translations remain valid! A few messages were changed because of stray whitespace characters: msgid "" "Slices always borrow from another object. In this example, `a` has to remain " -"'alive' (in scope) for at least as long as our slice. " +"'alive' (in scope) for at least as long as our slice." msgstr "" The formatting is enforced in CI and we will have to see how annoying this is in practice for the many contributors. If it becomes annoying, we should look into fixing dprint/check#11 so that `dprint` can annotate the lines that need fixing directly, then I think we can consider more strict formatting checks. I added more customization to `rustfmt.toml`. This is to better emulate the dense style used in the course: - `max_width = 85` allows lines to take up the full width available in our code blocks (when taking margins and the line numbers into account). - `wrap_comments = true` ensures that we don't show very long comments in the code examples. I edited some comments to shorten them and avoid unnecessary line breaks — please trim other unnecessarily long comments when you see them! Remember we're writing code for slides 😄 - `use_small_heuristics = "Max"` allows for things like struct literals and if-statements to take up the full line width configured above. The formatting settings apply to all our Rust code right now — I think we could improve this with https://github.com/dprint/dprint/issues/711 which lets us add per-directory `dprint` configuration files. However, the `inherit: true` setting is not yet implemented (as far as I can tell), so a nested configuration file will have to copy most or all of the top-level file.
This commit is contained in:
@ -7,4 +7,3 @@ publish = false
|
||||
[[bin]]
|
||||
name = "generics"
|
||||
path = "exercise.rs"
|
||||
|
||||
|
@ -48,18 +48,9 @@ fn min<T: LessThan>(l: T, r: T) -> T {
|
||||
|
||||
// ANCHOR: main
|
||||
fn main() {
|
||||
let cit1 = Citation {
|
||||
author: "Shapiro",
|
||||
year: 2011,
|
||||
};
|
||||
let cit2 = Citation {
|
||||
author: "Baumann",
|
||||
year: 2010,
|
||||
};
|
||||
let cit3 = Citation {
|
||||
author: "Baumann",
|
||||
year: 2019,
|
||||
};
|
||||
let cit1 = Citation { author: "Shapiro", year: 2011 };
|
||||
let cit2 = Citation { author: "Baumann", year: 2010 };
|
||||
let cit3 = Citation { author: "Baumann", year: 2019 };
|
||||
debug_assert_eq!(min(cit1, cit2), cit2);
|
||||
debug_assert_eq!(min(cit2, cit3), cit2);
|
||||
debug_assert_eq!(min(cit1, cit3), cit3);
|
||||
|
@ -31,13 +31,17 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* *Q:* Why `T` is specified twice in `impl<T> Point<T> {}`? Isn't that redundant?
|
||||
* This is because it is a generic implementation section for generic type. They are independently generic.
|
||||
* It means these methods are defined for any `T`.
|
||||
* It is possible to write `impl Point<u32> { .. }`.
|
||||
* `Point` is still generic and you can use `Point<f64>`, but methods in this block will only be available for `Point<u32>`.
|
||||
- _Q:_ Why `T` is specified twice in `impl<T> Point<T> {}`? Isn't that
|
||||
redundant?
|
||||
- This is because it is a generic implementation section for generic type.
|
||||
They are independently generic.
|
||||
- It means these methods are defined for any `T`.
|
||||
- It is possible to write `impl Point<u32> { .. }`.
|
||||
- `Point` is still generic and you can use `Point<f64>`, but methods in this
|
||||
block will only be available for `Point<u32>`.
|
||||
|
||||
* Try declaring a new variable `let p = Point { x: 5, y: 10.0 };`.
|
||||
Update the code to allow points that have elements of different types, by using two type variables, e.g., `T` and `U`.
|
||||
- Try declaring a new variable `let p = Point { x: 5, y: 10.0 };`. Update the
|
||||
code to allow points that have elements of different types, by using two type
|
||||
variables, e.g., `T` and `U`.
|
||||
|
||||
</details>
|
||||
|
@ -5,8 +5,7 @@ minutes: 5
|
||||
# Generic Functions
|
||||
|
||||
Rust supports generics, which lets you abstract algorithms or data structures
|
||||
(such as sorting or a binary tree)
|
||||
over the types used or stored.
|
||||
(such as sorting or a binary tree) over the types used or stored.
|
||||
|
||||
```rust,editable
|
||||
/// Pick `even` or `odd` depending on the value of `n`.
|
||||
@ -26,16 +25,16 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* Rust infers a type for T based on the types of the arguments and return value.
|
||||
- Rust infers a type for T based on the types of the arguments and return value.
|
||||
|
||||
* This is similar to C++ templates, but Rust partially compiles the generic
|
||||
- This is similar to C++ templates, but Rust partially compiles the generic
|
||||
function immediately, so that function must be valid for all types matching
|
||||
the constraints. For example, try modifying `pick` to return `even + odd` if
|
||||
`n == 0`. Even if only the `pick` instantiation with integers is used, Rust
|
||||
still considers it invalid. C++ would let you do this.
|
||||
|
||||
* Generic code is turned into non-generic code based on the call sites.
|
||||
This is a zero-cost abstraction: you get exactly the same result as if you had
|
||||
- Generic code is turned into non-generic code based on the call sites. This is
|
||||
a zero-cost abstraction: you get exactly the same result as if you had
|
||||
hand-coded the data structures without the abstraction.
|
||||
|
||||
</details>
|
||||
|
@ -30,20 +30,22 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
`impl Trait` allows you to work with types which you cannot name.
|
||||
The meaning of `impl Trait` is a bit different in the different positions.
|
||||
`impl Trait` allows you to work with types which you cannot name. The meaning of
|
||||
`impl Trait` is a bit different in the different positions.
|
||||
|
||||
* For a parameter, `impl Trait` is like an anonymous generic parameter with a trait bound.
|
||||
- For a parameter, `impl Trait` is like an anonymous generic parameter with a
|
||||
trait bound.
|
||||
|
||||
* For a return type, it means that the return type is some concrete type that implements the trait,
|
||||
without naming the type. This can be useful when you don't want to expose the concrete type in a
|
||||
public API.
|
||||
- For a return type, it means that the return type is some concrete type that
|
||||
implements the trait, without naming the type. This can be useful when you
|
||||
don't want to expose the concrete type in a public API.
|
||||
|
||||
Inference is hard in return position. A function returning `impl Foo` picks
|
||||
the concrete type it returns, without writing it out in the source. A function
|
||||
returning a generic type like `collect<B>() -> B` can return any type
|
||||
satisfying `B`, and the caller may need to choose one, such as with `let x:
|
||||
Vec<_> = foo.collect()` or with the turbofish, `foo.collect::<Vec<_>>()`.
|
||||
satisfying `B`, and the caller may need to choose one, such as with
|
||||
`let x: Vec<_> = foo.collect()` or with the turbofish,
|
||||
`foo.collect::<Vec<_>>()`.
|
||||
|
||||
What is the type of `debuggable`? Try `let debuggable: () = ..` to see what the
|
||||
error message shows.
|
||||
|
@ -25,11 +25,11 @@ fn main() {
|
||||
|
||||
<details>
|
||||
|
||||
* Try making a `NonClonable` and passing it to `duplicate`.
|
||||
- Try making a `NonClonable` and passing it to `duplicate`.
|
||||
|
||||
* When multiple traits are necessary, use `+` to join them.
|
||||
- When multiple traits are necessary, use `+` to join them.
|
||||
|
||||
* Show a `where` clause, students will encounter it when reading code.
|
||||
- Show a `where` clause, students will encounter it when reading code.
|
||||
|
||||
```rust,ignore
|
||||
fn duplicate<T>(a: T) -> (T, T)
|
||||
@ -38,13 +38,14 @@ fn main() {
|
||||
{
|
||||
(a.clone(), a.clone())
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
* It declutters the function signature if you have many parameters.
|
||||
* It has additional features making it more powerful.
|
||||
* If someone asks, the extra feature is that the type on the left of ":" can be arbitrary, like `Option<T>`.
|
||||
- It declutters the function signature if you have many parameters.
|
||||
- It has additional features making it more powerful.
|
||||
- If someone asks, the extra feature is that the type on the left of ":" can
|
||||
be arbitrary, like `Option<T>`.
|
||||
|
||||
* Note that Rust does not (yet) support specialization. For example, given the
|
||||
- Note that Rust does not (yet) support specialization. For example, given the
|
||||
original `duplicate`, it is invalid to add a specialized `duplicate(a: u32)`.
|
||||
|
||||
</details>
|
||||
|
Reference in New Issue
Block a user