Formatter (#51)

Enforce consistent formatting use `dprint`
This commit is contained in:
Luca Palmieri
2024-05-24 17:00:03 +02:00
committed by GitHub
parent 537118574b
commit 99591a715e
157 changed files with 1057 additions and 1044 deletions

View File

@@ -14,20 +14,20 @@ pub trait Deref {
}
```
They both feature type parameters.
In the case of `From`, it's a generic parameter, `T`.
They both feature type parameters.\
In the case of `From`, it's a generic parameter, `T`.\
In the case of `Deref`, it's an associated type, `Target`.
What's the difference? Why use one over the other?
## At most one implementation
Due to how deref coercion works, there can only be one "target" type for a given type. E.g. `String` can
only deref to `str`.
Due to how deref coercion works, there can only be one "target" type for a given type. E.g. `String` can
only deref to `str`.
It's about avoiding ambiguity: if you could implement `Deref` multiple times for a type,
which `Target` type should the compiler choose when you call a `&self` method?
That's why `Deref` uses an associated type, `Target`.
That's why `Deref` uses an associated type, `Target`.\
An associated type is uniquely determined **by the trait implementation**.
Since you can't implement `Deref` more than once, you'll only be able to specify one `Target` for a given type
and there won't be any ambiguity.
@@ -51,7 +51,7 @@ impl From<u16> for WrappingU32 {
}
```
This works because `From<u16>` and `From<u32>` are considered **different traits**.
This works because `From<u16>` and `From<u32>` are considered **different traits**.\
There is no ambiguity: the compiler can determine which implementation to use based on type of the value being converted.
## Case study: `Add`
@@ -73,7 +73,7 @@ It uses both mechanisms:
### `RHS`
`RHS` is a generic parameter to allow for different types to be added together.
`RHS` is a generic parameter to allow for different types to be added together.\
For example, you'll find these two implementations in the standard library:
```rust
@@ -109,10 +109,10 @@ because `u32` implements `Add<&u32>` _as well as_ `Add<u32>`.
### `Output`
`Output` represents the type of the result of the addition.
`Output` represents the type of the result of the addition.
Why do we need `Output` in the first place? Can't we just use `Self` as output, the type implementing `Add`?
We could, but it would limit the flexibility of the trait. In the standard library, for example, you'll find
Why do we need `Output` in the first place? Can't we just use `Self` as output, the type implementing `Add`?
We could, but it would limit the flexibility of the trait. In the standard library, for example, you'll find
this implementation:
```rust
@@ -125,9 +125,9 @@ impl Add<&u32> for &u32 {
}
```
The type they're implementing the trait for is `&u32`, but the result of the addition is `u32`.
It would be impossible[^flexible] to provide this implementation if `add` had to return `Self`, i.e. `&u32` in this case.
`Output` lets `std` decouple the implementor from the return type, thus supporting this case.
The type they're implementing the trait for is `&u32`, but the result of the addition is `u32`.\
It would be impossible[^flexible] to provide this implementation if `add` had to return `Self`, i.e. `&u32` in this case.
`Output` lets `std` decouple the implementor from the return type, thus supporting this case.
On the other hand, `Output` can't be a generic parameter. The output type of the operation **must** be uniquely determined
once the types of the operands are known. That's why it's an associated type: for a given combination of implementor
@@ -138,7 +138,7 @@ and generic parameters, there is only one `Output` type.
To recap:
- Use an **associated type** when the type must be uniquely determined for a given trait implementation.
- Use a **generic parameter** when you want to allow multiple implementations of the trait for the same type,
- Use a **generic parameter** when you want to allow multiple implementations of the trait for the same type,
with different input types.
## References
@@ -146,6 +146,5 @@ To recap:
- The exercise for this section is located in `exercises/04_traits/10_assoc_vs_generic`
[^flexible]: Flexibility is rarely free: the trait definition is more complex due to `Output`, and implementors have to reason about
what they want to return. The trade-off is only justified if that flexibility is actually needed. Keep that in mind
when designing your own traits.
what they want to return. The trade-off is only justified if that flexibility is actually needed. Keep that in mind
when designing your own traits.