Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarification on Deref coercion

Tags:

rust

Consider this example:

fn main() {
    let string: String = "A string".to_string();
    let string_ref: &String = &string;
    let str_ref_a: &str = string_ref;  // A
    let str_ref_b: &str = &string;     // B
}

How exactly are lines A and B different? string_ref is of type &String, so my understanding is that in line A we have an example of Deref coercion. What about line B though? Is it correct to say that it has nothing to do with Deref coercion and we simply have "a direct borrowing of a String as str", due to this:

impl Borrow<str> for String {
    #[inline]
    fn borrow(&self) -> &str {
        &self[..]
    }
}
like image 288
at54321 Avatar asked Oct 24 '25 17:10

at54321


2 Answers

No. Both lines involve deref coercion.

The Borrow trait is not special in any way - it is not known to the compiler (not a lang item). The Deref trait is.

The difference between Deref and Borrow (and also AsRef) is that Deref can only have one implementation for a type (since Target is an associated type and not a generic parameter) while AsRef (and Borrow) take a generic parameter and thus can be implemented multiple times. This is because Deref is for smart pointers: you should implement Deref<Target = T> if I am a T (note that the accurate definition of "smart pointer" is in flux). String is a str (plus additional features), and Vec is a slice. Box<T> is T.

On the other hand, AsRef and Borrow are conversion traits. I should implement AsRef<T> if I can be viewed as T. String can be viewed as str. But take e.g. str and OsStr. str is not an OsStr. But it can be treated like it if it was. So it implements AsRef<OsStr>. Borrow is the same as AsRef except it has additional requirements (namely, it should have the same Eq, Hash and Ord as the original value).

like image 65
Chayim Friedman Avatar answered Oct 27 '25 11:10

Chayim Friedman


Both are essentially equivalent and involve deref coercion:

let str_ref_a: &str = string_ref;  // A
let str_ref_b: &str = &string;     // B

The value string above is of type String, so the expression &string is of type &String which coerces into &str due to deref coercion as String implements Deref<Target=str>.


Regarding your question about Borrow: No, you aren't calling borrow() on the string value. Instead, that would be:

let str_ref_b: &str = string.borrow(); // Borrow::borrow() on String

That is, unlike deref(), the call to borrow() isn't inserted automatically.

like image 32
ネロク・ゴ Avatar answered Oct 27 '25 09:10

ネロク・ゴ