diff options
| author | bors <bors@rust-lang.org> | 2015-03-25 01:42:42 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-03-25 01:42:42 +0000 |
| commit | 593db005d4dbce2ff72009c1ba03477b031b2c0f (patch) | |
| tree | b585f5625dde7ab0af35fb3dd41a67ba0507f525 /src/doc | |
| parent | 123a754cb8356d0e78837dd4e58103ad801309ff (diff) | |
| parent | 3021d4c56422e15331e38f4b7b04c7229e024fda (diff) | |
| download | rust-593db005d4dbce2ff72009c1ba03477b031b2c0f.tar.gz rust-593db005d4dbce2ff72009c1ba03477b031b2c0f.zip | |
Auto merge of #23681 - alexcrichton:rollup, r=alexcrichton
Diffstat (limited to 'src/doc')
| -rw-r--r-- | src/doc/reference.md | 6 | ||||
| -rw-r--r-- | src/doc/trpl/SUMMARY.md | 1 | ||||
| -rw-r--r-- | src/doc/trpl/associated-types.md | 202 | ||||
| -rw-r--r-- | src/doc/trpl/ownership.md | 4 | ||||
| -rw-r--r-- | src/doc/trpl/unsafe.md | 17 |
5 files changed, 217 insertions, 13 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md index 07df3bdad34..32088b2ab67 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1265,7 +1265,7 @@ be undesired. * Sending signals * Accessing/modifying the file system * Unsigned integer overflow (well-defined as wrapping) -* Signed integer overflow (well-defined as two's complement representation +* Signed integer overflow (well-defined as two’s complement representation wrapping) #### Diverging functions @@ -2961,10 +2961,10 @@ meaning of the operators on standard types is given here. : Exclusive or. Calls the `bitxor` method of the `std::ops::BitXor` trait. * `<<` - : Logical left shift. + : Left shift. Calls the `shl` method of the `std::ops::Shl` trait. * `>>` - : Logical right shift. + : Right shift. Calls the `shr` method of the `std::ops::Shr` trait. #### Lazy boolean operators diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 76f8b6c9738..70c74825a07 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -22,6 +22,7 @@ * [More Strings](more-strings.md) * [Patterns](patterns.md) * [Method Syntax](method-syntax.md) + * [Associated Types](associated-types.md) * [Closures](closures.md) * [Iterators](iterators.md) * [Generics](generics.md) diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md new file mode 100644 index 00000000000..f36c2c56b6a --- /dev/null +++ b/src/doc/trpl/associated-types.md @@ -0,0 +1,202 @@ +% Associated Types + +Associated types are a powerful part of Rust's type system. They're related to +the idea of a 'type family', in other words, grouping multiple types together. That +description is a bit abstract, so let's dive right into an example. If you want +to write a `Graph` trait, you have two types to be generic over: the node type +and the edge type. So you might write a trait, `Graph<N, E>`, that looks like +this: + +```rust +trait Graph<N, E> { + fn has_edge(&self, &N, &N) -> bool; + fn edges(&self, &N) -> Vec<E>; + // etc +} +``` + +While this sort of works, it ends up being awkward. For example, any function +that wants to take a `Graph` as a parameter now _also_ needs to be generic over +the `N`ode and `E`dge types too: + +```rust,ignore +fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... } +``` + +Our distance calculation works regardless of our `Edge` type, so the `E` stuff in +this signature is just a distraction. + +What we really want to say is that a certain `E`dge and `N`ode type come together +to form each kind of `Graph`. We can do that with associated types: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec<Self::E>; + // etc +} +``` + +Now, our clients can be abstract over a given `Graph`: + +```rust,ignore +fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... } +``` + +No need to deal with the `E`dge type here! + +Let's go over all this in more detail. + +## Defining associated types + +Let's build that `Graph` trait. Here's the definition: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec<Self::E>; +} +``` + +Simple enough. Associated types use the `type` keyword, and go inside the body +of the trait, with the functions. + +These `type` declarations can have all the same thing as functions do. For example, +if we wanted our `N` type to implement `Display`, so we can print the nodes out, +we could do this: + +```rust +use std::fmt; + +trait Graph { + type N: fmt::Display; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec<Self::E>; +} +``` + +## Implementing associated types + +Just like any trait, traits that use associated types use the `impl` keyword to +provide implementations. Here's a simple implementation of Graph: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec<Self::E>; +# } +struct Node; + +struct Edge; + +struct MyGraph; + +impl Graph for MyGraph { + type N = Node; + type E = Edge; + + fn has_edge(&self, n1: &Node, n2: &Node) -> bool { + true + } + + fn edges(&self, n: &Node) -> Vec<Edge> { + Vec::new() + } +} +``` + +This silly implementation always returns `true` and an empty `Vec<Edge>`, but it +gives you an idea of how to implement this kind of thing. We first need three +`struct`s, one for the graph, one for the node, and one for the edge. If it made +more sense to use a different type, that would work as well, we're just going to +use `struct`s for all three here. + +Next is the `impl` line, which is just like implementing any other trait. + +From here, we use `=` to define our associated types. The name the trait uses +goes on the left of the `=`, and the concrete type we're `impl`ementing this +for goes on the right. Finally, we use the concrete types in our function +declarations. + +## Trait objects with associated types + +There’s one more bit of syntax we should talk about: trait objects. If you +try to create a trait object from an associated type, like this: + +```rust,ignore +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec<Self::E>; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec<Edge> { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box<Graph>; +``` + +You’ll get two errors: + +```text +error: the value of the associated type `E` (from the trait `main::Graph`) must +be specified [E0191] +let obj = Box::new(graph) as Box<Graph>; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +24:44 error: the value of the associated type `N` (from the trait +`main::Graph`) must be specified [E0191] +let obj = Box::new(graph) as Box<Graph>; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +We can’t create a trait object like this, becuase we don’t know the associated +types. Instead, we can write this: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec<Self::E>; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec<Edge> { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>; +``` + +The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` +type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we +couldn’t be sure which `impl` to match this trait object to. diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 6aced23ede0..b851f19d22d 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -513,8 +513,8 @@ Otherwise, it is an error to elide an output lifetime. ### Examples -Here are some examples of functions with elided lifetimes, and the version of -what the elided lifetimes are expand to: +Here are some examples of functions with elided lifetimes. We've paired each +example of an elided lifetime with its expanded form. ```{rust,ignore} fn print(s: &str); // elided diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 2116976d55a..dbf0cae6f4b 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -197,15 +197,16 @@ use std::ptr; // Define a wrapper around the handle returned by the foreign code. // Unique<T> has the same semantics as Box<T> -pub struct Unique<T> { +// +// NB: For simplicity and correctness, we require that T has kind Send +// (owned boxes relax this restriction). +pub struct Unique<T: Send> { // It contains a single raw, mutable pointer to the object in question. ptr: *mut T } // Implement methods for creating and using the values in the box. -// NB: For simplicity and correctness, we require that T has kind Send -// (owned boxes relax this restriction). impl<T: Send> Unique<T> { pub fn new(value: T) -> Unique<T> { unsafe { @@ -239,11 +240,11 @@ impl<T: Send> Unique<T> { // Unique<T>, making the struct manage the raw pointer: when the // struct goes out of scope, it will automatically free the raw pointer. // -// NB: This is an unsafe destructor, because rustc will not normally -// allow destructors to be associated with parameterized types, due to -// bad interaction with managed boxes. (With the Send restriction, -// we don't have this problem.) Note that the `#[unsafe_destructor]` -// feature gate is required to use unsafe destructors. +// NB: This is an unsafe destructor; rustc will not normally allow +// destructors to be associated with parameterized types (due to +// historically failing to check them soundly). Note that the +// `#[unsafe_destructor]` feature gate is currently required to use +// unsafe destructors. #[unsafe_destructor] impl<T: Send> Drop for Unique<T> { fn drop(&mut self) { |
