Auto merge of #27544 - steveklabnik:rollup, r=steveklabnik

- Successful merges: #27285, #27524, #27533, #27535, #27538, #27539
- Failed merges:
This commit is contained in:
bors 2015-08-05 21:34:19 +00:00
commit a0eb7a2c6d
9 changed files with 228 additions and 19 deletions

View File

@ -316,6 +316,35 @@ assert_eq!(3, answer);
Now we take a trait object, a `&Fn`. And we have to make a reference
to our closure when we pass it to `call_with_one`, so we use `&||`.
# Function pointers and closures
A function pointer is kind of like a closure that has no environment. As such,
you can pass a function pointer to any function expecting a closure argument,
and it will work:
```rust
fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
some_closure(1)
}
fn add_one(i: i32) -> i32 {
i + 1
}
let f = add_one;
let answer = call_with_one(&f);
assert_eq!(2, answer);
```
In this example, we dont strictly need the intermediate variable `f`,
the name of the function works just fine too:
```ignore
let answer = call_with_one(&add_one);
```
# Returning closures
Its very common for functional-style code to return closures in various

View File

@ -227,3 +227,34 @@ as any type:
let x: i32 = diverges();
let x: String = diverges();
```
## Function pointers
We can also create variable bindings which point to functions:
```rust
let f: fn(i32) -> i32;
```
`f` is a variable binding which points to a function that takes an `i32` as
an argument and returns an `i32`. For example:
```rust
fn plus_one(i: i32) -> i32 {
i + 1
}
// without type inference
let f: fn(i32) -> i32 = plus_one;
// with type inference
let f = plus_one;
```
We can then use `f` to call the function:
```rust
# fn plus_one(i: i32) -> i32 { i + 1 }
# let f = plus_one;
let six = f(5);
```

View File

@ -6,7 +6,7 @@ Generics are called parametric polymorphism in type theory,
which means that they are types or functions that have multiple forms (poly
is multiple, morph is form) over a given parameter (parametric).
Anyway, enough with type theory, lets check out some generic code. Rusts
Anyway, enough type theory, lets check out some generic code. Rusts
standard library provides a type, `Option<T>`, thats generic:
```rust
@ -27,7 +27,7 @@ let x: Option<i32> = Some(5);
In the type declaration, we say `Option<i32>`. Note how similar this looks to
`Option<T>`. So, in this particular `Option`, `T` has the value of `i32`. On
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`.
the right-hand side of the binding, we make a `Some(T)`, where `T` is `5`.
Since thats an `i32`, the two sides match, and Rust is happy. If they didnt
match, wed get an error:
@ -101,11 +101,6 @@ fn takes_two_things<T, U>(x: T, y: U) {
}
```
Generic functions are most useful with trait bounds, which well cover in the
[section on traits][traits].
[traits]: traits.html
## Generic structs
You can store a generic type in a `struct` as well:
@ -122,3 +117,28 @@ let float_origin = Point { x: 0.0, y: 0.0 };
Similarly to functions, the `<T>` is where we declare the generic parameters,
and we then use `x: T` in the type declaration, too.
When you want to add an implementation for the generic struct, you just
declare the type parameter after the `impl`:
```rust
# struct Point<T> {
# x: T,
# y: T,
# }
#
impl<T> Point<T> {
fn swap(&mut self) {
std::mem::swap(&mut self.x, &mut self.y);
}
}
```
So far youve seen generics that take absolutely any type. These are useful in
many cases: youve already seen `Option<T>`, and later youll meet universal
container types like [`Vec<T>`][Vec]. On the other hand, often you want to
trade that flexibility for increased expressive power. Read about [trait
bounds][traits] to see why and how.
[traits]: traits.html
[Vec]: ../std/vec/struct.Vec.html

View File

@ -533,7 +533,7 @@ Great! Next up: lets compare our guess to the secret guess.
# Comparing guesses
Now that weve got user input, lets compare our guess to the random guess.
Heres our next step, though it doesnt quite work yet:
Heres our next step, though it doesnt quite compile yet:
```rust,ignore
extern crate rand;
@ -617,7 +617,7 @@ match guess.cmp(&secret_number) {
If its `Less`, we print `Too small!`, if its `Greater`, `Too big!`, and if
`Equal`, `You win!`. `match` is really useful, and is used often in Rust.
I did mention that this wont quite work yet, though. Lets try it:
I did mention that this wont quite compile yet, though. Lets try it:
```bash
$ cargo build

View File

@ -77,8 +77,18 @@ Before we get to that, though, lets break the explicit example down:
fn bar<'a>(...)
```
This part declares our lifetimes. This says that `bar` has one lifetime, `'a`.
If we had two reference parameters, it would look like this:
We previously talked a little about [function syntax][functions], but we didnt
discuss the `<>`s after a functions name. A function can have generic
parameters between the `<>`s, of which lifetimes are one kind. Well discuss
other kinds of generics [later in the book][generics], but for now, lets
just focus on the lifteimes aspect.
[functions]: functions.html
[generics]: generics.html
We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
`'a`. If we had two reference parameters, it would look like this:
```rust,ignore
fn bar<'a, 'b>(...)

View File

@ -81,3 +81,55 @@ will let you do this:
let p: Point = // ...
let x: f64 = p + 2i32;
```
# Using operator traits in generic structs
Now that we know how operator traits are defined, we can define our `HasArea`
trait and `Square` struct from the [traits chapter][traits] more generically:
[traits]: traits.html
```rust
use std::ops::Mul;
trait HasArea<T> {
fn area(&self) -> T;
}
struct Square<T> {
x: T,
y: T,
side: T,
}
impl<T> HasArea<T> for Square<T>
where T: Mul<Output=T> + Copy {
fn area(&self) -> T {
self.side * self.side
}
}
fn main() {
let s = Square {
x: 0.0f64,
y: 0.0f64,
side: 12.0f64,
};
println!("Area of s: {}", s.area());
}
```
For `HasArea` and `Square`, we just declare a type parameter `T` and replace
`f64` with it. The `impl` needs more involved modifications:
```ignore
impl<T> HasArea<T> for Square<T>
where T: Mul<Output=T> + Copy { ... }
```
The `area` method requires that we can multiply the sides, so we declare that
type `T` must implement `std::ops::Mul`. Like `Add`, mentioned above, `Mul`
itself takes an `Output` parameter: since we know that numbers don't change
type when multiplied, we also set it to `T`. `T` must also support copying, so
Rust doesn't try to move `self.side` into the return value.

View File

@ -47,8 +47,11 @@ As you can see, the `trait` block looks very similar to the `impl` block,
but we dont define a body, just a type signature. When we `impl` a trait,
we use `impl Trait for Item`, rather than just `impl Item`.
We can use traits to constrain our generics. Consider this function, which
does not compile:
## Traits bounds for generic functions
Traits are useful because they allow a type to make certain promises about its
behavior. Generic functions can exploit this to constrain the types they
accept. Consider this function, which does not compile:
```rust,ignore
fn print_area<T>(shape: T) {
@ -75,7 +78,7 @@ fn print_area<T: HasArea>(shape: T) {
}
```
The syntax `<T: HasArea>` means `any type that implements the HasArea trait`.
The syntax `<T: HasArea>` means “any type that implements the `HasArea` trait.”
Because traits define function type signatures, we can be sure that any type
which implements `HasArea` will have an `.area()` method.
@ -152,6 +155,63 @@ We get a compile-time error:
error: the trait `HasArea` is not implemented for the type `_` [E0277]
```
## Traits bounds for generic structs
Your generic structs can also benefit from trait constraints. All you need to
do is append the constraint when you declare type parameters. Here is a new
type `Rectangle<T>` and its operation `is_square()`:
```rust
struct Rectangle<T> {
x: T,
y: T,
width: T,
height: T,
}
impl<T: PartialEq> Rectangle<T> {
fn is_square(&self) -> bool {
self.width == self.height
}
}
fn main() {
let mut r = Rectangle {
x: 0,
y: 0,
width: 47,
height: 47,
};
assert!(r.is_square());
r.height = 42;
assert!(!r.is_square());
}
```
`is_square()` needs to check that the sides are equal, so the sides must be of
a type that implements the [`core::cmp::PartialEq`][PartialEq] trait:
```ignore
impl<T: PartialEq> Rectangle<T> { ... }
```
Now, a rectangle can be defined in terms of any type that can be compared for
equality.
[PartialEq]: ../core/cmp/trait.PartialEq.html
Here we defined a new struct `Rectangle` that accepts numbers of any
precision—really, objects of pretty much any type—as long as they can be
compared for equality. Could we do the same for our `HasArea` structs, `Square`
and `Circle`? Yes, but they need multiplication, and to work with that we need
to know more about [operator traits][operators-and-overloading].
[operators-and-overloading]: operators-and-overloading.html
# Rules for implementing traits
So far, weve only added trait implementations to structs, but you can
implement a trait for any type. So technically, we _could_ implement `HasArea`
for `i32`:
@ -175,7 +235,7 @@ impl HasArea for i32 {
It is considered poor style to implement methods on such primitive types, even
though it is possible.
This may seem like the Wild West, but there are two other restrictions around
This may seem like the Wild West, but there are two restrictions around
implementing traits that prevent this from getting out of hand. The first is
that if the trait isnt defined in your scope, it doesnt apply. Heres an
example: the standard library provides a [`Write`][write] trait which adds
@ -340,10 +400,10 @@ This shows off the additional feature of `where` clauses: they allow bounds
where the left-hand side is an arbitrary type (`i32` in this case), not just a
plain type parameter (like `T`).
## Default methods
# Default methods
Theres one last feature of traits we should cover: default methods. Its
easiest just to show an example:
If you already know how a typical implementor will define a method, you can
let your trait supply a default:
```rust
trait Foo {

View File

@ -38,6 +38,9 @@ use self::Cow::*;
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
///
/// If you are implementing `Borrow` and both `Self` and `Borrowed` implement
/// `Hash`, `Eq`, and/or `Ord`, they must produce the same result.
///
/// `Borrow` is very similar to, but different than, `AsRef`. See
/// [the book][book] for more.
///

View File

@ -273,7 +273,11 @@ macro_rules! impls{
/// even though it does not. This allows you to inform the compiler about certain safety properties
/// of your code.
///
/// Though they both have scary names, `PhantomData<T>` and "phantom types" are unrelated. 👻👻👻
/// # A ghastly note 👻👻👻
///
/// Though they both have scary names, `PhantomData<T>` and 'phantom types' are related, but not
/// identical. Phantom types are a more general concept that don't require `PhantomData<T>` to
/// implement, but `PhantomData<T>` is the most common way to implement them in a correct manner.
///
/// # Examples
///