Rollup merge of #24722 - steveklabnik:doc_deref, r=alexcrichton

r? @alexcrichton
This commit is contained in:
Steve Klabnik 2015-04-24 22:54:24 -04:00
commit 831232b767
2 changed files with 121 additions and 5 deletions

View File

@ -1,3 +1,119 @@
% `Deref` coercions % `Deref` coercions
Coming soon! The standard library provides a special trait, [`Deref`][deref]. Its 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, theres a language
feature related to `Deref`: deref coercions. Heres the rule: If you have a
type `U`, and it implements `Deref<Target=T>`, values of `&U` will
automatically coerce to a `&T`. Heres 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.
Thats 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 weve done is wrap our `String` in an `Rc<T>`. But we can now pass the
`Rc<String>` around anywhere wed have a `String`. The signature of `foo`
didnt 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` isnt a reference, and `foo` takes `&self`, this works.
Thats 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 its inserting `*`s, that uses `Deref`.

View File

@ -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
Heres how it works: Heres 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 were returning a `Circle`. With this method, we can grow a new We just say were 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. Heres a You can also define methods that do not take a `self` parameter. Heres a
pattern thats very common in Rust code: pattern thats 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
Lets say that we want our users to be able to create Circles, but we will Lets 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`