&&str --> &str coercion

Hey there! A rust beginner here.

I've been reading a bit about typing, and came up with a code example that I thought wouldn't compile, but did:

pub struct A {
    name: String
}

impl A {
    fn name(&self) -> &str {
        &self.name.trim() // &&str is coerced to &str
    }
}

How come in this instance rust decides to dereference this here? Does this combat the usual principle that type coercion must be explicit? Is there a way I could get &&str without the borrow checker yelling at me for returning a reference to something owned by the returning function?

1 Like

Unfortunately, the only thing that "lives" after the function returns is the owned String inside the struct. You can freely return borrows on that (&self -> &'self str) but returning a &&str requires the &str to live (be "owned" in a sense) outside the function.

Think, for example, what would the 'a refer to in the return type you're proposing: &'a &'self str

Yes, that's why you don't implement Deref judiciously. But it is implemented for &T thus things work here.

For that to work you need to explain who would own that &str… there are not &str in the String bowels so who would own it?

To be precise: the things we call “coercions” in Rust are precisely those changes of type which are implicit. In this case, you are using “deref coercion”.

1 Like

No. But why would you want to? If the caller wants a &&str, they can do &a.name().

3 Likes

Thank you for the explanations everyone! Very helpful.

When you perform a deref coercion on &'short &'long T, Rust gives you a &'long T. That's why it works.

This is different from mutable references where &'short mut &'long mut T does indeed coerce down to &'short mut T.

2 Likes

No because trim(&str) gives you a new &str, that &str needs to be stored somewhere, in this case the stack of the current function and will be dropped at the end of the fucntion so it cannot be borrowed outside it, you should instead just return the new &str.
what you wrote compiles because it's doing &(*trim(self.name)) basically it sees that the return type is &str so &... must be trying to borrow a str since the &str that you get out of trim has lifetime self you just dereference it to get the str to reborrow