diff --git a/Deref Trait.md b/Deref Trait.md index 8c7181f..a39f702 100644 --- a/Deref Trait.md +++ b/Deref Trait.md @@ -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` 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` + +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` value. + +Due to us implementing the `Deref` trait on `MyBox`, Rust can turn `&MyBox` 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` +```rust +fn main() { + let m = MyBox::new(String::from("Rust")); + hello(&(*m)[..]); +} +``` + +The `(*m)` dereferences the `MyBox` 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` +- From `&mut T` to `&mut U` when `T: DerefMut` +- From `&mut T` to `&U` when `T: Deref` + +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. \ No newline at end of file