The standard library provides a special trait, Deref
`Deref`. It’s normally
used to overload *
`*`, the dereference operator:
use std::ops::Deref; 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); }
This is useful for writing custom pointer types. However, there’s a language
feature related to Deref
`Deref: ‘deref coercions’. Here’s the rule: If you have a type
`: ‘deref coercions’. Here’s the rule: If you have a
type U
`U, and it implements
`, and it implements Deref<Target=T>
`Deref, values of
`, values of &U
`&Uwill automatically coerce to a
` will
automatically coerce to a &T
`&T`. Here’s an example:
fn foo(s: &str) { // borrow a string for a second } // String implements Deref<Target=str> let owned = "Hello".to_string(); // therefore, this works: foo(&owned);
Using an ampersand in front of a value takes a reference to it. So owned
`ownedis a
` is a
String
`String,
`, &owned
`&ownedis an
` is an &String
`&String, and since
`, and since impl Deref<Target=str> for String
`impl Deref,
`, &String
`&Stringwill deref to
` will deref to &str
`&str, which
`, which foo()
`foo()` takes.
That’s it. This rule is one of the only places in which Rust does an automatic
conversion for you, but it adds a lot of flexibility. For example, the Rc<T>
`Rctype implements
`
type implements Deref<Target=T>
`Deref
use std::rc::Rc; fn foo(s: &str) { // borrow a string for a second } // String implements Deref<Target=str> let owned = "Hello".to_string(); let counted = Rc::new(owned); // therefore, this works: foo(&counted);
All we’ve done is wrap our String
`Stringin an
` in an Rc<T>
`Rc. But we can now pass the
`. But we can now pass the
Rc<String>
`Rcaround anywhere we’d have a
` around anywhere we’d have a String
`String. The signature of
`. The signature of foo
`foodidn’t change, but works just as well with either type. This example has two conversions:
`
didn’t change, but works just as well with either type. This example has two
conversions: Rc<String>
`Rcto
` to String
`Stringand then
` and then String
`Stringto
` to &str
`&str`. Rust will do
this as many times as possible until the types match.
Another very common implementation provided by the standard library is:
fn main() { fn foo(s: &[i32]) { // borrow a slice for a second } // Vec<T> implements Deref<Target=[T]> let owned = vec![1, 2, 3]; foo(&owned); }fn foo(s: &[i32]) { // borrow a slice for a second } // Vec<T> implements Deref<Target=[T]> let owned = vec![1, 2, 3]; foo(&owned);
Vectors can Deref
`Deref` to a slice.
Deref
`Deref` will also kick in when calling a method. In other words, these are
the same two things in Rust:
struct Foo; impl Foo { fn foo(&self) { println!("Foo"); } } let f = Foo; f.foo();
Even though f
`fisn’t a reference, and
` isn’t a reference, and foo
`footakes
` takes &self
`&self`, this works.
That’s because these things are the same:
f.foo(); (&f).foo(); (&&f).foo(); (&&&&&&&&f).foo();
A value of type &&&&&&&&&&&&&&&&Foo
`&&&&&&&&&&&&&&&&Foocan still have methods defined on
` can still have methods defined on Foo
`Foocalled, because the compiler will insert as many * operations as necessary to get it right. And since it’s inserting
`
called, because the compiler will insert as many * operations as necessary to
get it right. And since it’s inserting *
`*s, that uses
`s, that uses Deref
`Deref`.