mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 04:54:17 -06:00
finished ch15.2
This commit is contained in:
parent
856e0e992a
commit
78b0782ac9
@ -221,3 +221,101 @@ This then matches the `5` in `assert_eq!`
|
||||
|
||||
For example a deref coercion can convert `&String` to `&str` because `String` implemented the `Deref` trait such that it returns `&str`.
|
||||
|
||||
Deref coercion is a convenience that Rust perfomrs on args to functions and methods.
|
||||
|
||||
This only works on tpyes that implement the `Deref` trait.
|
||||
|
||||
It happens automatically when we pass a reference to a particular type's value as an arg to a function or method that doesn't match the parameter type in the function or method definition.
|
||||
|
||||
A sequence of calls to the `deref` method converts the type we provided into the type the parameter needs.
|
||||
|
||||
Deref coercion was added to Rust so that rogrammers writing function and method calls don't need to add as many explicit references and dereferences with `&` and `*`.
|
||||
|
||||
This feature also lets us write more code that can code that can work for either references or smart pointers.
|
||||
|
||||
To see deref coercion in action we will use `MyBox<T>` type defined previously with the implementation of `Deref` as well.
|
||||
|
||||
This example shows the definition of a function that has a string slice parameter
|
||||
```rust
|
||||
fn hello(name: &str) {
|
||||
println!("Hello, {name}!");
|
||||
}
|
||||
```
|
||||
We can call the `hello` function with a string slice as an arg.
|
||||
|
||||
Such as `hello("Rust");` as an example.
|
||||
|
||||
With Deref coercion makes it possible to call `hello` with a reference to a value of type `MyBox<String>`
|
||||
|
||||
Here is an example of this
|
||||
```rust
|
||||
fn main() {
|
||||
let m = MyBox::new(String::from("Rust"));
|
||||
hello(&m);
|
||||
}
|
||||
```
|
||||
Here we call the `hello` function with the arg `&m`, which is a reference to a `MyBox<String>` value.
|
||||
|
||||
Due to us implementing the `Deref` trait on `MyBox<T>`, Rust can turn `&MyBox<String>` into a `&String` by calling deref.
|
||||
|
||||
The std library then proves an implementation of `Deref` on `String` that reutnrs a string slice.
|
||||
|
||||
This is in the API docs for `Deref`.
|
||||
|
||||
Rust then calls `deref` again to turn the `&String` into `&str`. This matches the `hello` function definition.
|
||||
|
||||
If Rust didn't implement deref coercion we would have to wrtie does like this instead to call `hello` with a value of type `&MyBox<String>`
|
||||
```rust
|
||||
fn main() {
|
||||
let m = MyBox::new(String::from("Rust"));
|
||||
hello(&(*m)[..]);
|
||||
}
|
||||
```
|
||||
|
||||
The `(*m)` dereferences the `MyBox<String>` into a `String`.
|
||||
|
||||
The `&` and `[..]` takes a string slice of the `String` that is equal to the whole string to match the signature of `hello`.
|
||||
|
||||
This code without deref coercions is much harder to read, wrtie and understand, escpially with all of the symbols involved.
|
||||
|
||||
Deref coercion allows Rusts to handle all of these conversions automatically.
|
||||
|
||||
When the `Deref` trait is defined for the types involved.
|
||||
|
||||
Rust will analyze the types and use `Deref::deref` as many times as necessary to get a reference to match the param type.
|
||||
|
||||
The number of times that `Deref::deref` needs to be inserted is resolved at compile time.
|
||||
|
||||
There is no runtime penalty for taking advantage of deref coercion.
|
||||
|
||||
## How Deref Coercion Interacts with Mutability
|
||||
Similar to how you would use `Deref` to override the `*` operator on immutable references, you can use the `DerefMut` trait to override the `*` operator on mutable references.
|
||||
|
||||
Rust does deref coercion when it finds tpyes and trait implelemtations in there cases
|
||||
- From `&T` to `&U` when `T: Deref<Target=U>`
|
||||
- From `&mut T` to `&mut U` when `T: DerefMut<Target=U>`
|
||||
- From `&mut T` to `&U` when `T: Deref<Target=U>`
|
||||
|
||||
The fist two cases are the same expect that the second implements mutablility.
|
||||
|
||||
The first one states that if you have a `&T` and `T` implements `Deref` to some type `U` you can get a `&U` transparently
|
||||
|
||||
The second states that the smae deref coercion happens for mutable references.
|
||||
|
||||
The third one is tricker.
|
||||
|
||||
Rust will also coerce a mutable reference to an immutable one.
|
||||
|
||||
The reverse is *not* possible: immutable references will never coerce to mutable refernces.
|
||||
|
||||
This is due to the borrowing rules, if you have a mutable reference, that mutable reference must be the only reference to that data.
|
||||
|
||||
(The program will not compile if otherwise)
|
||||
|
||||
Converting one mutable reference to one immutable reference will never break the borrowing rules.
|
||||
|
||||
Converting an immutable reference to a mutable reference would require that the intial immutable reference is the only immutable reference to that data.
|
||||
|
||||
Borrowing rukes don't gaurantee that.
|
||||
|
||||
Therefore Rust can't make that assumption that converting an immutable reference to a mutable reference is possible.
|
Loading…
x
Reference in New Issue
Block a user