2
votes

Here is modified version of example of usage Deref:

use std::ops::Deref;
use std::rc::Rc;

#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
pub struct InternedString {
    string: Rc<String>,
}

impl InternedString {
    #[inline]
    pub fn new(string: &'static str) -> InternedString {
        InternedString {
            string: Rc::new(string.to_owned()),
        }
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &str { &self.string }
}


struct DerefExample<T> {
    value: T
}

impl<T> Deref for DerefExample<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

fn main() {
    let x = DerefExample { value: 'a' };
    assert_eq!('a', *x);

    match *x {
        'a' => (),
        _ => (),
    };

    let s = InternedString::new("aaa");
    match *s {
        "test" => (),
        _ => (),
    };
}

it is not compiled, with error:

55 |         "test" => (),
   |         ^^^^^^ expected str, found reference
   |
   = note: expected type `str`
   = note:    found type `&'static str`

but if I call deref method by hands:

match s.deref() {
    "test" => (),
    _ => (),
}

all compiled without errors, what is difference between *s and s.deref(), and why for char all works fine?

1

1 Answers

4
votes

Character literals are of type char, while string literals are of type &'static str. Note that string literals are always references, while character literals are not references.

*s is actually translated to *(s.deref()), not to s.deref(), when performing a deref coercion, because deref returns a reference. Thus, to match an InternedString against a string literal, you need to take a reference to *s, i.e. you need to write &*s instead of *s. That works because *s yields an lvalue.