...
Step-by-step, how to understand the describe() function example
(assuming I understand this)
Part A
We can implement methods directly on shared reference types themselves. There is no deref coercion then when called on a shared reference that is of that shared reference type (playground)
In a sense then the method implemented, when called on a shared reference, takes ownership of the shared reference, per se, not the value the shared reference points to.
Code Block | ||
---|---|---|
| ||
use std::borrow::Cow;
trait CustomInto<T> {
fn custom_into(self) -> T;
}
impl<'a> CustomInto<Cow<'a, str>> for &'a str {
fn custom_into(self) -> Cow<'a, str> {
Cow::Borrowed(self)
}
}
fn main(){
let _cow = "hello there".custom_into();
} |
Note how the implementation is for the ref string slice type, not the primitive string slice type.
Part B
Consider two traits
From<String>
From<&'a str>
Cow<'a, str> The enum Cow<str> implements both traits
Cow has the associated function
fn from(s: String) → Cow<'a str>Cow<str>
Cow has another associated function
fn from(s: &'a str) → Cow<'a str>
Consider the additional trait
Into<'a, Cow<'a str>>
String automatically implements Into, as does str, given that the From traits are implemented
Both String and str implement Into with a method of the following form
fn into(self) → Cow<a' str>
Cow<str>
Consider another trait
Into<Cow<str>>
A From implementation implies that there is a corresponding Into implementation. There is a blanket implementation of Into in the standard library. My guess is that the following code is the blanket implementation
Code Block language rust impl<T,U> Into<U> for T where U: From<T> { fn into(self) -> U { U::from(self) } }
Therefore String implements the Into<Cow<str>> trait
Code Block language rust impl<'a> Into<Cow<'a, str>> for String { fn into(self) -> Cow<'a, str> { ... } }
Also &str implements the Into<Cow<str>> trait
Code Block impl<'a> Into<Cow<'a, str>> for &'a str { fn into(self) -> Cow<'a, str> { ... } }
In the first four arms of the match expression, there are string literals upon which the method into() is called. We know the methods must have a return type of these method calls must return a Cow<'static, str>.
A string literal is of type &str, a shared reference to a string slice
A string literal has a static lifetime.
When applying the method Therefore the result of calling the into() method on a string literal is a Cow<'static, the string literal is dereferenced into a string slice strThen the method into() can be applied on the str. We have already seen that this method existsstr>
So, we see now how the first four arms of the match expression work.
In the last arm of the match expression, there is a String upon which the method into() is called. This method call must return a Cow<'static, str>
We can call the into() method on a String to get a Cow<str> without any lifetime limitations between the String and the Cow<str>
So the returned Cow<str> can be annotated with a static lifetime, without requiring that the String had to have one, too.
So, we see now how the fifth arm of the match expression works.