Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Step-by-step, how to understand the describe() function example

(assuming I understand this, which is an if, a small if, but an if)

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.

...

Note how the implementation is for the ref string slice type, not the primitive string slice type.

Part B

...

  1. Consider two traits

    1. From<String>

    2. From<&'a str>

  2. Cow<'a, str> The enum Cow<str> implements both traits

    1. Cow has the associated function
      fn from(s: String) → Cow<'a, str>Cow<str>

    2. Cow has another associated function
      fn from(s: &'a str) → Cow<'a, str>

  3. Therefore String implements<

  4. Consider the additional trait

    1. Into<Cow<'a, str>>

  5. String automatically implements Into, as does str, given that the From traits are implemented

  6. Both String and str implement Into with a method of the following form

    1. fn into(self) → Cow<a', str>Cow<str>

  7. Consider another trait

    1. Into<Cow<str>>

  8. 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
    languagerust
    impl<T,U> Into<U> for T
       where U: From<T> {
       
      fn into(self) -> U {
        U::from(self)
      }  
    }
  9. Therefore String implements the Into<Cow<str>> trait

    Code Block
    languagerust
    impl<'a> Into<Cow<'a, str>> for String {
      fn into(self) -> Cow<'a, str> {
        ...
      }
    }
  10. 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> {
        ...
      }
    }
  11. 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>.

  12. A string literal is of type &str, a shared reference to a string slice

  13. A string literal has a static lifetime.

  14. When applying the method Therefore the result of calling the into() method on a string literal is a Cow<'static, str>

  15. So, 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 existswe see now how the first four arms of the match expression work.

  16. 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>

  17. 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>

  18. So the returned Cow<str> can be annotated with a static lifetime, without requiring that the String had to have one, too.

  19. So, we see now how the fifth arm of the match expression works.