Rollup merge of #24722 - steveklabnik:doc_deref, r=alexcrichton
r? @alexcrichton
This commit is contained in:
commit
831232b767
@ -1,3 +1,119 @@
|
|||||||
% `Deref` coercions
|
% `Deref` coercions
|
||||||
|
|
||||||
Coming soon!
|
The standard library provides a special trait, [`Deref`][deref]. It’s normally
|
||||||
|
used to overload `*`, the dereference operator:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[deref]: ../std/ops/trait.Deref.html
|
||||||
|
|
||||||
|
This is useful for writing custom pointer types. However, there’s a language
|
||||||
|
feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
|
||||||
|
type `U`, and it implements `Deref<Target=T>`, values of `&U` will
|
||||||
|
automatically coerce to a `&T`. Here’s an example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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` is a
|
||||||
|
`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
|
||||||
|
String`, `&String` will deref to `&str`, which `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>`
|
||||||
|
type implements `Deref<Target=T>`, so this works:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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` in an `Rc<T>`. But we can now pass the
|
||||||
|
`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
|
||||||
|
didn’t change, but works just as well with either type. This example has two
|
||||||
|
conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
|
||||||
|
this as many times as possible until the types match.
|
||||||
|
|
||||||
|
Another very common implementation provided by the standard library is:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
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` to a slice.
|
||||||
|
|
||||||
|
## Deref and method calls
|
||||||
|
|
||||||
|
`Deref` will also kick in when calling a method. In other words, these are
|
||||||
|
the same two things in Rust:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn foo(&self) { println!("Foo"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Foo;
|
||||||
|
|
||||||
|
f.foo();
|
||||||
|
```
|
||||||
|
|
||||||
|
Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
|
||||||
|
That’s because these things are the same:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
f.foo();
|
||||||
|
(&f).foo();
|
||||||
|
(&&f).foo();
|
||||||
|
(&&&&&&&&f).foo();
|
||||||
|
```
|
||||||
|
|
||||||
|
A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo`
|
||||||
|
called, because the compiler will insert as many * operations as necessary to
|
||||||
|
get it right. And since it’s inserting `*`s, that uses `Deref`.
|
||||||
|
@ -18,7 +18,7 @@ foo.bar().baz();
|
|||||||
Luckily, as you may have guessed with the leading question, you can! Rust provides
|
Luckily, as you may have guessed with the leading question, you can! Rust provides
|
||||||
the ability to use this ‘method call syntax’ via the `impl` keyword.
|
the ability to use this ‘method call syntax’ via the `impl` keyword.
|
||||||
|
|
||||||
## Method calls
|
# Method calls
|
||||||
|
|
||||||
Here’s how it works:
|
Here’s how it works:
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ impl Circle {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Chaining method calls
|
# Chaining method calls
|
||||||
|
|
||||||
So, now we know how to call a method, such as `foo.bar()`. But what about our
|
So, now we know how to call a method, such as `foo.bar()`. But what about our
|
||||||
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
|
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
|
||||||
@ -127,7 +127,7 @@ fn grow(&self) -> Circle {
|
|||||||
We just say we’re returning a `Circle`. With this method, we can grow a new
|
We just say we’re returning a `Circle`. With this method, we can grow a new
|
||||||
circle to any arbitrary size.
|
circle to any arbitrary size.
|
||||||
|
|
||||||
## Static methods
|
# Static methods
|
||||||
|
|
||||||
You can also define methods that do not take a `self` parameter. Here’s a
|
You can also define methods that do not take a `self` parameter. Here’s a
|
||||||
pattern that’s very common in Rust code:
|
pattern that’s very common in Rust code:
|
||||||
@ -158,7 +158,7 @@ This ‘static method’ builds a new `Circle` for us. Note that static methods
|
|||||||
are called with the `Struct::method()` syntax, rather than the `ref.method()`
|
are called with the `Struct::method()` syntax, rather than the `ref.method()`
|
||||||
syntax.
|
syntax.
|
||||||
|
|
||||||
## Builder Pattern
|
# Builder Pattern
|
||||||
|
|
||||||
Let’s say that we want our users to be able to create Circles, but we will
|
Let’s say that we want our users to be able to create Circles, but we will
|
||||||
allow them to only set the properties they care about. Otherwise, the `x`
|
allow them to only set the properties they care about. Otherwise, the `x`
|
||||||
|
Loading…
Reference in New Issue
Block a user