mirror of
https://github.com/rust-lang/rust
synced 2024-11-02 10:21:05 +00:00
small edits for recently written book chapters
This commit is contained in:
parent
3860240b0e
commit
0070625495
5 changed files with 145 additions and 145 deletions
|
@ -1,8 +1,8 @@
|
|||
% 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
|
||||
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:
|
||||
|
@ -48,11 +48,11 @@ 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.
|
||||
Let’s go over all this in more detail.
|
||||
|
||||
## Defining associated types
|
||||
|
||||
Let's build that `Graph` trait. Here's the definition:
|
||||
Let’s build that `Graph` trait. Here’s the definition:
|
||||
|
||||
```rust
|
||||
trait Graph {
|
||||
|
@ -86,7 +86,7 @@ trait Graph {
|
|||
## 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:
|
||||
provide implementations. Here’s a simple implementation of Graph:
|
||||
|
||||
```rust
|
||||
# trait Graph {
|
||||
|
@ -118,13 +118,13 @@ impl Graph for MyGraph {
|
|||
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
|
||||
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
|
||||
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.
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
% Closures
|
||||
|
||||
Rust not only has named functions, but anonymous functions as well. Anonymous
|
||||
functions that have an associated environment are called 'closures', because they
|
||||
functions that have an associated environment are called ‘closures’, because they
|
||||
close over an environment. Rust has a really great implementation of them, as
|
||||
we'll see.
|
||||
we’ll see.
|
||||
|
||||
# Syntax
|
||||
|
||||
|
@ -15,7 +15,7 @@ let plus_one = |x: i32| x + 1;
|
|||
assert_eq!(2, plus_one(1));
|
||||
```
|
||||
|
||||
We create a binding, `plus_one`, and assign it to a closure. The closure's
|
||||
We create a binding, `plus_one`, and assign it to a closure. The closure’s
|
||||
arguments go between the pipes (`|`), and the body is an expression, in this
|
||||
case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line
|
||||
closures too:
|
||||
|
@ -33,7 +33,7 @@ let plus_two = |x| {
|
|||
assert_eq!(4, plus_two(2));
|
||||
```
|
||||
|
||||
You'll notice a few things about closures that are a bit different than regular
|
||||
You’ll notice a few things about closures that are a bit different than regular
|
||||
functions defined with `fn`. The first of which is that we did not need to
|
||||
annotate the types of arguments the closure takes or the values it returns. We
|
||||
can:
|
||||
|
@ -44,13 +44,13 @@ let plus_one = |x: i32| -> i32 { x + 1 };
|
|||
assert_eq!(2, plus_one(1));
|
||||
```
|
||||
|
||||
But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
||||
But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
|
||||
While specifying the full type for named functions is helpful with things like
|
||||
documentation and type inference, the types of closures are rarely documented
|
||||
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
|
||||
that inferring named function types can.
|
||||
|
||||
The second is that the syntax is similar, but a bit different. I've added spaces
|
||||
The second is that the syntax is similar, but a bit different. I’ve added spaces
|
||||
here to make them look a little closer:
|
||||
|
||||
```rust
|
||||
|
@ -59,11 +59,11 @@ let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
|
|||
let plus_one_v3 = |x: i32 | x + 1 ;
|
||||
```
|
||||
|
||||
Small differences, but they're similar in ways.
|
||||
Small differences, but they’re similar in ways.
|
||||
|
||||
# Closures and their environment
|
||||
|
||||
Closures are called such because they 'close over their environment.' It
|
||||
Closures are called such because they ‘close over their environment’. It
|
||||
looks like this:
|
||||
|
||||
```rust
|
||||
|
@ -105,7 +105,7 @@ fn main() {
|
|||
^
|
||||
```
|
||||
|
||||
A verbose yet helpful error message! As it says, we can't take a mutable borrow
|
||||
A verbose yet helpful error message! As it says, we can’t take a mutable borrow
|
||||
on `num` because the closure is already borrowing it. If we let the closure go
|
||||
out of scope, we can:
|
||||
|
||||
|
@ -140,7 +140,7 @@ let takes_nums = || nums;
|
|||
```
|
||||
|
||||
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
|
||||
in our closure, we have to take ownership of `nums`. It's the same as if we'd
|
||||
in our closure, we have to take ownership of `nums`. It’s the same as if we’d
|
||||
passed `nums` to a function that took ownership of it.
|
||||
|
||||
## `move` closures
|
||||
|
@ -156,7 +156,7 @@ let owns_num = move |x: i32| x + num;
|
|||
|
||||
Now, even though the keyword is `move`, the variables follow normal move semantics.
|
||||
In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy
|
||||
of `num`. So what's the difference?
|
||||
of `num`. So what’s the difference?
|
||||
|
||||
```rust
|
||||
let mut num = 5;
|
||||
|
@ -171,11 +171,11 @@ assert_eq!(10, num);
|
|||
```
|
||||
|
||||
So in this case, our closure took a mutable reference to `num`, and then when
|
||||
we called `add_num`, it mutated the underlying value, as we'd expect. We also
|
||||
we called `add_num`, it mutated the underlying value, as we’d expect. We also
|
||||
needed to declare `add_num` as `mut` too, because we’re mutating its
|
||||
environment.
|
||||
|
||||
If we change to a `move` closure, it's different:
|
||||
If we change to a `move` closure, it’s different:
|
||||
|
||||
```rust
|
||||
let mut num = 5;
|
||||
|
@ -203,8 +203,8 @@ you tons of control over what your code does, and closures are no different.
|
|||
|
||||
# Closure implementation
|
||||
|
||||
Rust's implementation of closures is a bit different than other languages. They
|
||||
are effectively syntax sugar for traits. You'll want to make sure to have read
|
||||
Rust’s implementation of closures is a bit different than other languages. They
|
||||
are effectively syntax sugar for traits. You’ll want to make sure to have read
|
||||
the [traits chapter][traits] before this one, as well as the chapter on [trait
|
||||
objects][trait-objects].
|
||||
|
||||
|
@ -237,9 +237,9 @@ pub trait FnOnce<Args> {
|
|||
# }
|
||||
```
|
||||
|
||||
You'll notice a few differences between these traits, but a big one is `self`:
|
||||
You’ll notice a few differences between these traits, but a big one is `self`:
|
||||
`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This
|
||||
covers all three kinds of `self` via the usual method call syntax. But we've
|
||||
covers all three kinds of `self` via the usual method call syntax. But we’ve
|
||||
split them up into three traits, rather than having a single one. This gives us
|
||||
a large amount of control over what kind of closures we can take.
|
||||
|
||||
|
@ -253,7 +253,7 @@ Now that we know that closures are traits, we already know how to accept and
|
|||
return closures: just like any other trait!
|
||||
|
||||
This also means that we can choose static vs dynamic dispatch as well. First,
|
||||
let's write a function which takes something callable, calls it, and returns
|
||||
let’s write a function which takes something callable, calls it, and returns
|
||||
the result:
|
||||
|
||||
```rust
|
||||
|
@ -271,7 +271,7 @@ assert_eq!(3, answer);
|
|||
We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it
|
||||
suggests: it calls the closure, giving it `1` as an argument.
|
||||
|
||||
Let's examine the signature of `call_with_one` in more depth:
|
||||
Let’s examine the signature of `call_with_one` in more depth:
|
||||
|
||||
```rust
|
||||
fn call_with_one<F>(some_closure: F) -> i32
|
||||
|
@ -280,7 +280,7 @@ fn call_with_one<F>(some_closure: F) -> i32
|
|||
```
|
||||
|
||||
We take one parameter, and it has the type `F`. We also return a `i32`. This part
|
||||
isn't interesting. The next part is:
|
||||
isn’t interesting. The next part is:
|
||||
|
||||
```rust
|
||||
# fn call_with_one<F>(some_closure: F) -> i32
|
||||
|
@ -292,9 +292,9 @@ Because `Fn` is a trait, we can bound our generic with it. In this case, our clo
|
|||
takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
|
||||
is `Fn(i32) -> i32`.
|
||||
|
||||
There's one other key point here: because we're bounding a generic with a
|
||||
trait, this will get monomorphized, and therefore, we'll be doing static
|
||||
dispatch into the closure. That's pretty neat. In many langauges, closures are
|
||||
There’s one other key point here: because we’re bounding a generic with a
|
||||
trait, this will get monomorphized, and therefore, we’ll be doing static
|
||||
dispatch into the closure. That’s pretty neat. In many langauges, closures are
|
||||
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
|
||||
we can stack allocate our closure environment, and statically dispatch the
|
||||
call. This happens quite often with iterators and their adapters, which often
|
||||
|
@ -320,7 +320,7 @@ to our closure when we pass it to `call_with_one`, so we use `&||`.
|
|||
|
||||
It’s very common for functional-style code to return closures in various
|
||||
situations. If you try to return a closure, you may run into an error. At
|
||||
first, it may seem strange, but we'll figure it out. Here's how you'd probably
|
||||
first, it may seem strange, but we’ll figure it out. Here’s how you’d probably
|
||||
try to return a closure from a function:
|
||||
|
||||
```rust,ignore
|
||||
|
@ -361,7 +361,7 @@ In order to return something from a function, Rust needs to know what
|
|||
size the return type is. But since `Fn` is a trait, it could be various
|
||||
things of various sizes: many different types can implement `Fn`. An easy
|
||||
way to give something a size is to take a reference to it, as references
|
||||
have a known size. So we'd write this:
|
||||
have a known size. So we’d write this:
|
||||
|
||||
```rust,ignore
|
||||
fn factory() -> &(Fn(i32) -> Vec<i32>) {
|
||||
|
@ -385,7 +385,7 @@ fn factory() -> &(Fn(i32) -> i32) {
|
|||
```
|
||||
|
||||
Right. Because we have a reference, we need to give it a lifetime. But
|
||||
our `factory()` function takes no arguments, so elision doesn't kick in
|
||||
our `factory()` function takes no arguments, so elision doesn’t kick in
|
||||
here. What lifetime can we choose? `'static`:
|
||||
|
||||
```rust,ignore
|
||||
|
@ -414,7 +414,7 @@ error: mismatched types:
|
|||
|
||||
```
|
||||
|
||||
This error is letting us know that we don't have a `&'static Fn(i32) -> i32`,
|
||||
This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
|
||||
we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
|
||||
|
||||
Because each closure generates its own environment `struct` and implementation
|
||||
|
@ -422,7 +422,7 @@ of `Fn` and friends, these types are anonymous. They exist just solely for
|
|||
this closure. So Rust shows them as `closure <anon>`, rather than some
|
||||
autogenerated name.
|
||||
|
||||
But why doesn't our closure implement `&'static Fn`? Well, as we discussed before,
|
||||
But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before,
|
||||
closures borrow their environment. And in this case, our environment is based
|
||||
on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
|
||||
of the stack frame. So if we returned this closure, the function call would be
|
||||
|
@ -445,7 +445,7 @@ assert_eq!(6, answer);
|
|||
# }
|
||||
```
|
||||
|
||||
We use a trait object, by `Box`ing up the `Fn`. There's just one last problem:
|
||||
We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
|
||||
|
||||
```text
|
||||
error: `num` does not live long enough
|
||||
|
@ -471,5 +471,5 @@ assert_eq!(6, answer);
|
|||
```
|
||||
|
||||
By making the inner closure a `move Fn`, we create a new stack frame for our
|
||||
closure. By `Box`ing it up, we've given it a known size, and allowing it to
|
||||
closure. By `Box`ing it up, we’ve given it a known size, and allowing it to
|
||||
escape our stack frame.
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
% Crates and Modules
|
||||
|
||||
When a project starts getting large, it's considered good software
|
||||
When a project starts getting large, it’s considered good software
|
||||
engineering practice to split it up into a bunch of smaller pieces, and then
|
||||
fit them together. It's also important to have a well-defined interface, so
|
||||
fit them together. It’s also important to have a well-defined interface, so
|
||||
that some of your functionality is private, and some is public. To facilitate
|
||||
these kinds of things, Rust has a module system.
|
||||
|
||||
# Basic terminology: Crates and Modules
|
||||
|
||||
Rust has two distinct terms that relate to the module system: *crate* and
|
||||
*module*. A crate is synonymous with a *library* or *package* in other
|
||||
languages. Hence "Cargo" as the name of Rust's package management tool: you
|
||||
Rust has two distinct terms that relate to the module system: ‘crate’ and
|
||||
‘module’. A crate is synonymous with a ‘library’ or ‘package’ in other
|
||||
languages. Hence “Cargo” as the name of Rust’s package management tool: you
|
||||
ship your crates to others with Cargo. Crates can produce an executable or a
|
||||
library, depending on the project.
|
||||
|
||||
|
@ -18,10 +18,10 @@ Each crate has an implicit *root module* that contains the code for that crate.
|
|||
You can then define a tree of sub-modules under that root module. Modules allow
|
||||
you to partition your code within the crate itself.
|
||||
|
||||
As an example, let's make a *phrases* crate, which will give us various phrases
|
||||
in different languages. To keep things simple, we'll stick to "greetings" and
|
||||
"farewells" as two kinds of phrases, and use English and Japanese (日本語) as
|
||||
two languages for those phrases to be in. We'll use this module layout:
|
||||
As an example, let’s make a *phrases* crate, which will give us various phrases
|
||||
in different languages. To keep things simple, we’ll stick to ‘greetings’ and
|
||||
‘farewells’ as two kinds of phrases, and use English and Japanese (日本語) as
|
||||
two languages for those phrases to be in. We’ll use this module layout:
|
||||
|
||||
```text
|
||||
+-----------+
|
||||
|
@ -47,7 +47,7 @@ In this example, `phrases` is the name of our crate. All of the rest are
|
|||
modules. You can see that they form a tree, branching out from the crate
|
||||
*root*, which is the root of the tree: `phrases` itself.
|
||||
|
||||
Now that we have a plan, let's define these modules in code. To start,
|
||||
Now that we have a plan, let’s define these modules in code. To start,
|
||||
generate a new crate with Cargo:
|
||||
|
||||
```bash
|
||||
|
@ -72,7 +72,7 @@ above.
|
|||
|
||||
# Defining Modules
|
||||
|
||||
To define each of our modules, we use the `mod` keyword. Let's make our
|
||||
To define each of our modules, we use the `mod` keyword. Let’s make our
|
||||
`src/lib.rs` look like this:
|
||||
|
||||
```
|
||||
|
@ -101,7 +101,7 @@ Within a given `mod`, you can declare sub-`mod`s. We can refer to sub-modules
|
|||
with double-colon (`::`) notation: our four nested modules are
|
||||
`english::greetings`, `english::farewells`, `japanese::greetings`, and
|
||||
`japanese::farewells`. Because these sub-modules are namespaced under their
|
||||
parent module, the names don't conflict: `english::greetings` and
|
||||
parent module, the names don’t conflict: `english::greetings` and
|
||||
`japanese::greetings` are distinct, even though their names are both
|
||||
`greetings`.
|
||||
|
||||
|
@ -116,11 +116,11 @@ build deps examples libphrases-a7448e02a0468eaa.rlib native
|
|||
```
|
||||
|
||||
`libphrase-hash.rlib` is the compiled crate. Before we see how to use this
|
||||
crate from another crate, let's break it up into multiple files.
|
||||
crate from another crate, let’s break it up into multiple files.
|
||||
|
||||
# Multiple file crates
|
||||
|
||||
If each crate were just one file, these files would get very large. It's often
|
||||
If each crate were just one file, these files would get very large. It’s often
|
||||
easier to split up crates into multiple files, and Rust supports this in two
|
||||
ways.
|
||||
|
||||
|
@ -141,7 +141,7 @@ mod english;
|
|||
If we do that, Rust will expect to find either a `english.rs` file, or a
|
||||
`english/mod.rs` file with the contents of our module.
|
||||
|
||||
Note that in these files, you don't need to re-declare the module: that's
|
||||
Note that in these files, you don’t need to re-declare the module: that’s
|
||||
already been done with the initial `mod` declaration.
|
||||
|
||||
Using these two techniques, we can break up our crate into two directories and
|
||||
|
@ -180,7 +180,7 @@ mod japanese;
|
|||
|
||||
These two declarations tell Rust to look for either `src/english.rs` and
|
||||
`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending
|
||||
on our preference. In this case, because our modules have sub-modules, we've
|
||||
on our preference. In this case, because our modules have sub-modules, we’ve
|
||||
chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
|
||||
like this:
|
||||
|
||||
|
@ -192,11 +192,11 @@ mod farewells;
|
|||
Again, these declarations tell Rust to look for either
|
||||
`src/english/greetings.rs` and `src/japanese/greetings.rs` or
|
||||
`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because
|
||||
these sub-modules don't have their own sub-modules, we've chosen to make them
|
||||
these sub-modules don’t have their own sub-modules, we’ve chosen to make them
|
||||
`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew!
|
||||
|
||||
The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are
|
||||
both empty at the moment. Let's add some functions.
|
||||
both empty at the moment. Let’s add some functions.
|
||||
|
||||
Put this in `src/english/greetings.rs`:
|
||||
|
||||
|
@ -223,7 +223,7 @@ fn hello() -> String {
|
|||
```
|
||||
|
||||
Of course, you can copy and paste this from this web page, or just type
|
||||
something else. It's not important that you actually put "konnichiwa" to learn
|
||||
something else. It’s not important that you actually put ‘konnichiwa’ to learn
|
||||
about the module system.
|
||||
|
||||
Put this in `src/japanese/farewells.rs`:
|
||||
|
@ -234,17 +234,17 @@ fn goodbye() -> String {
|
|||
}
|
||||
```
|
||||
|
||||
(This is "Sayōnara", if you're curious.)
|
||||
(This is ‘Sayōnara’, if you’re curious.)
|
||||
|
||||
Now that we have some functionality in our crate, let's try to use it from
|
||||
Now that we have some functionality in our crate, let’s try to use it from
|
||||
another crate.
|
||||
|
||||
# Importing External Crates
|
||||
|
||||
We have a library crate. Let's make an executable crate that imports and uses
|
||||
We have a library crate. Let’s make an executable crate that imports and uses
|
||||
our library.
|
||||
|
||||
Make a `src/main.rs` and put this in it (it won't quite compile yet):
|
||||
Make a `src/main.rs` and put this in it (it won’t quite compile yet):
|
||||
|
||||
```rust,ignore
|
||||
extern crate phrases;
|
||||
|
@ -259,7 +259,7 @@ fn main() {
|
|||
```
|
||||
|
||||
The `extern crate` declaration tells Rust that we need to compile and link to
|
||||
the `phrases` crate. We can then use `phrases`' modules in this one. As we
|
||||
the `phrases` crate. We can then use `phrases`’ modules in this one. As we
|
||||
mentioned earlier, you can use double colons to refer to sub-modules and the
|
||||
functions inside of them.
|
||||
|
||||
|
@ -267,10 +267,10 @@ Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate,
|
|||
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
||||
`src/main.rs`. This pattern is quite common for executable crates: most
|
||||
functionality is in a library crate, and the executable crate uses that
|
||||
library. This way, other programs can also use the library crate, and it's also
|
||||
library. This way, other programs can also use the library crate, and it’s also
|
||||
a nice separation of concerns.
|
||||
|
||||
This doesn't quite work yet, though. We get four errors that look similar to
|
||||
This doesn’t quite work yet, though. We get four errors that look similar to
|
||||
this:
|
||||
|
||||
```bash
|
||||
|
@ -287,14 +287,14 @@ note: in expansion of format_args!
|
|||
phrases/src/main.rs:4:5: 4:76 note: expansion site
|
||||
```
|
||||
|
||||
By default, everything is private in Rust. Let's talk about this in some more
|
||||
By default, everything is private in Rust. Let’s talk about this in some more
|
||||
depth.
|
||||
|
||||
# Exporting a Public Interface
|
||||
|
||||
Rust allows you to precisely control which aspects of your interface are
|
||||
public, and so private is the default. To make things public, you use the `pub`
|
||||
keyword. Let's focus on the `english` module first, so let's reduce our `src/main.rs`
|
||||
keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs`
|
||||
to just this:
|
||||
|
||||
```{rust,ignore}
|
||||
|
@ -306,21 +306,21 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
In our `src/lib.rs`, let's add `pub` to the `english` module declaration:
|
||||
In our `src/lib.rs`, let’s add `pub` to the `english` module declaration:
|
||||
|
||||
```{rust,ignore}
|
||||
pub mod english;
|
||||
mod japanese;
|
||||
```
|
||||
|
||||
And in our `src/english/mod.rs`, let's make both `pub`:
|
||||
And in our `src/english/mod.rs`, let’s make both `pub`:
|
||||
|
||||
```{rust,ignore}
|
||||
pub mod greetings;
|
||||
pub mod farewells;
|
||||
```
|
||||
|
||||
In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:
|
||||
In our `src/english/greetings.rs`, let’s add `pub` to our `fn` declaration:
|
||||
|
||||
```{rust,ignore}
|
||||
pub fn hello() -> String {
|
||||
|
@ -358,12 +358,12 @@ Goodbye in English: Goodbye.
|
|||
Now that our functions are public, we can use them. Great! However, typing out
|
||||
`phrases::english::greetings::hello()` is very long and repetitive. Rust has
|
||||
another keyword for importing names into the current scope, so that you can
|
||||
refer to them with shorter names. Let's talk about `use`.
|
||||
refer to them with shorter names. Let’s talk about `use`.
|
||||
|
||||
# Importing Modules with `use`
|
||||
|
||||
Rust has a `use` keyword, which allows us to import names into our local scope.
|
||||
Let's change our `src/main.rs` to look like this:
|
||||
Let’s change our `src/main.rs` to look like this:
|
||||
|
||||
```{rust,ignore}
|
||||
extern crate phrases;
|
||||
|
@ -378,7 +378,7 @@ fn main() {
|
|||
```
|
||||
|
||||
The two `use` lines import each module into the local scope, so we can refer to
|
||||
the functions by a much shorter name. By convention, when importing functions, it's
|
||||
the functions by a much shorter name. By convention, when importing functions, it’s
|
||||
considered best practice to import the module, rather than the function directly. In
|
||||
other words, you _can_ do this:
|
||||
|
||||
|
@ -395,7 +395,7 @@ fn main() {
|
|||
```
|
||||
|
||||
But it is not idiomatic. This is significantly more likely to introduce a
|
||||
naming conflict. In our short program, it's not a big deal, but as it grows, it
|
||||
naming conflict. In our short program, it’s not a big deal, but as it grows, it
|
||||
becomes a problem. If we have conflicting names, Rust will give a compilation
|
||||
error. For example, if we made the `japanese` functions public, and tried to do
|
||||
this:
|
||||
|
@ -423,7 +423,7 @@ error: aborting due to previous error
|
|||
Could not compile `phrases`.
|
||||
```
|
||||
|
||||
If we're importing multiple names from the same module, we don't have to type it out
|
||||
If we’re importing multiple names from the same module, we don’t have to type it out
|
||||
twice. Instead of this:
|
||||
|
||||
```{rust,ignore}
|
||||
|
@ -439,11 +439,11 @@ use phrases::english::{greetings, farewells};
|
|||
|
||||
## Re-exporting with `pub use`
|
||||
|
||||
You don't just use `use` to shorten identifiers. You can also use it inside of your crate
|
||||
You don’t just use `use` to shorten identifiers. You can also use it inside of your crate
|
||||
to re-export a function inside another module. This allows you to present an external
|
||||
interface that may not directly map to your internal code organization.
|
||||
|
||||
Let's look at an example. Modify your `src/main.rs` to read like this:
|
||||
Let’s look at an example. Modify your `src/main.rs` to read like this:
|
||||
|
||||
```{rust,ignore}
|
||||
extern crate phrases;
|
||||
|
@ -494,11 +494,11 @@ mod farewells;
|
|||
```
|
||||
|
||||
The `pub use` declaration brings the function into scope at this part of our
|
||||
module hierarchy. Because we've `pub use`d this inside of our `japanese`
|
||||
module hierarchy. Because we’ve `pub use`d this inside of our `japanese`
|
||||
module, we now have a `phrases::japanese::hello()` function and a
|
||||
`phrases::japanese::goodbye()` function, even though the code for them lives in
|
||||
`phrases::japanese::greetings::hello()` and
|
||||
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn't
|
||||
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn’t
|
||||
define our external interface.
|
||||
|
||||
Here we have a `pub use` for each function we want to bring into the
|
||||
|
@ -507,13 +507,13 @@ everything from `greetings` into the current scope: `pub use self::greetings::*`
|
|||
|
||||
What about the `self`? Well, by default, `use` declarations are absolute paths,
|
||||
starting from your crate root. `self` makes that path relative to your current
|
||||
place in the hierarchy instead. There's one more special form of `use`: you can
|
||||
place in the hierarchy instead. There’s one more special form of `use`: you can
|
||||
`use super::` to reach one level up the tree from your current location. Some
|
||||
people like to think of `self` as `.` and `super` as `..`, from many shells'
|
||||
people like to think of `self` as `.` and `super` as `..`, from many shells’
|
||||
display for the current directory and the parent directory.
|
||||
|
||||
Outside of `use`, paths are relative: `foo::bar()` refers to a function inside
|
||||
of `foo` relative to where we are. If that's prefixed with `::`, as in
|
||||
of `foo` relative to where we are. If that’s prefixed with `::`, as in
|
||||
`::foo::bar()`, it refers to a different `foo`, an absolute path from your
|
||||
crate root.
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
% Macros
|
||||
|
||||
By now you've learned about many of the tools Rust provides for abstracting and
|
||||
By now you’ve learned about many of the tools Rust provides for abstracting and
|
||||
reusing code. These units of code reuse have a rich semantic structure. For
|
||||
example, functions have a type signature, type parameters have trait bounds,
|
||||
and overloaded functions must belong to a particular trait.
|
||||
|
||||
This structure means that Rust's core abstractions have powerful compile-time
|
||||
This structure means that Rust’s core abstractions have powerful compile-time
|
||||
correctness checking. But this comes at the price of reduced flexibility. If
|
||||
you visually identify a pattern of repeated code, you may find it's difficult
|
||||
you visually identify a pattern of repeated code, you may find it’s difficult
|
||||
or cumbersome to express that pattern as a generic function, a trait, or
|
||||
anything else within Rust's semantics.
|
||||
anything else within Rust’s semantics.
|
||||
|
||||
Macros allow us to abstract at a *syntactic* level. A macro invocation is
|
||||
Macros allow us to abstract at a syntactic level. A macro invocation is
|
||||
shorthand for an "expanded" syntactic form. This expansion happens early in
|
||||
compilation, before any static checking. As a result, macros can capture many
|
||||
patterns of code reuse that Rust's core abstractions cannot.
|
||||
patterns of code reuse that Rust’s core abstractions cannot.
|
||||
|
||||
The drawback is that macro-based code can be harder to understand, because
|
||||
fewer of the built-in rules apply. Like an ordinary function, a well-behaved
|
||||
|
@ -23,8 +23,8 @@ difficult to design a well-behaved macro! Additionally, compiler errors in
|
|||
macro code are harder to interpret, because they describe problems in the
|
||||
expanded code, not the source-level form that developers use.
|
||||
|
||||
These drawbacks make macros something of a "feature of last resort". That's not
|
||||
to say that macros are bad; they are part of Rust because sometimes they're
|
||||
These drawbacks make macros something of a "feature of last resort". That’s not
|
||||
to say that macros are bad; they are part of Rust because sometimes they’re
|
||||
needed for truly concise, well-abstracted code. Just keep this tradeoff in
|
||||
mind.
|
||||
|
||||
|
@ -40,7 +40,7 @@ let x: Vec<u32> = vec![1, 2, 3];
|
|||
# assert_eq!(x, [1, 2, 3]);
|
||||
```
|
||||
|
||||
This can't be an ordinary function, because it takes any number of arguments.
|
||||
This can’t be an ordinary function, because it takes any number of arguments.
|
||||
But we can imagine it as syntactic shorthand for
|
||||
|
||||
```rust
|
||||
|
@ -77,20 +77,20 @@ macro_rules! vec {
|
|||
# }
|
||||
```
|
||||
|
||||
Whoa, that's a lot of new syntax! Let's break it down.
|
||||
Whoa, that’s a lot of new syntax! Let’s break it down.
|
||||
|
||||
```ignore
|
||||
macro_rules! vec { ... }
|
||||
```
|
||||
|
||||
This says we're defining a macro named `vec`, much as `fn vec` would define a
|
||||
function named `vec`. In prose, we informally write a macro's name with an
|
||||
This says we’re defining a macro named `vec`, much as `fn vec` would define a
|
||||
function named `vec`. In prose, we informally write a macro’s name with an
|
||||
exclamation point, e.g. `vec!`. The exclamation point is part of the invocation
|
||||
syntax and serves to distinguish a macro from an ordinary function.
|
||||
|
||||
## Matching
|
||||
|
||||
The macro is defined through a series of *rules*, which are pattern-matching
|
||||
The macro is defined through a series of rules, which are pattern-matching
|
||||
cases. Above, we had
|
||||
|
||||
```ignore
|
||||
|
@ -99,13 +99,13 @@ cases. Above, we had
|
|||
|
||||
This is like a `match` expression arm, but the matching happens on Rust syntax
|
||||
trees, at compile time. The semicolon is optional on the last (here, only)
|
||||
case. The "pattern" on the left-hand side of `=>` is known as a *matcher*.
|
||||
case. The "pattern" on the left-hand side of `=>` is known as a ‘matcher’.
|
||||
These have [their own little grammar] within the language.
|
||||
|
||||
[their own little grammar]: ../reference.html#macros
|
||||
|
||||
The matcher `$x:expr` will match any Rust expression, binding that syntax tree
|
||||
to the *metavariable* `$x`. The identifier `expr` is a *fragment specifier*;
|
||||
to the ‘metavariable’ `$x`. The identifier `expr` is a ‘fragment specifier’;
|
||||
the full possibilities are enumerated in the [advanced macros chapter][].
|
||||
Surrounding the matcher with `$(...),*` will match zero or more expressions,
|
||||
separated by commas.
|
||||
|
@ -158,8 +158,8 @@ Each matched expression `$x` will produce a single `push` statement in the
|
|||
macro expansion. The repetition in the expansion proceeds in "lockstep" with
|
||||
repetition in the matcher (more on this in a moment).
|
||||
|
||||
Because `$x` was already declared as matching an expression, we don't repeat
|
||||
`:expr` on the right-hand side. Also, we don't include a separating comma as
|
||||
Because `$x` was already declared as matching an expression, we don’t repeat
|
||||
`:expr` on the right-hand side. Also, we don’t include a separating comma as
|
||||
part of the repetition operator. Instead, we have a terminating semicolon
|
||||
within the repeated block.
|
||||
|
||||
|
@ -180,7 +180,7 @@ The outer braces are part of the syntax of `macro_rules!`. In fact, you can use
|
|||
The inner braces are part of the expanded syntax. Remember, the `vec!` macro is
|
||||
used in an expression context. To write an expression with multiple statements,
|
||||
including `let`-bindings, we use a block. If your macro expands to a single
|
||||
expression, you don't need this extra layer of braces.
|
||||
expression, you don’t need this extra layer of braces.
|
||||
|
||||
Note that we never *declared* that the macro produces an expression. In fact,
|
||||
this is not determined until we use the macro as an expression. With care, you
|
||||
|
@ -194,7 +194,7 @@ The repetition operator follows two principal rules:
|
|||
1. `$(...)*` walks through one "layer" of repetitions, for all of the `$name`s
|
||||
it contains, in lockstep, and
|
||||
2. each `$name` must be under at least as many `$(...)*`s as it was matched
|
||||
against. If it is under more, it'll be duplicated, as appropriate.
|
||||
against. If it is under more, it’ll be duplicated, as appropriate.
|
||||
|
||||
This baroque macro illustrates the duplication of variables from outer
|
||||
repetition levels.
|
||||
|
@ -219,7 +219,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
That's most of the matcher syntax. These examples use `$(...)*`, which is a
|
||||
That’s most of the matcher syntax. These examples use `$(...)*`, which is a
|
||||
"zero or more" match. Alternatively you can write `$(...)+` for a "one or
|
||||
more" match. Both forms optionally include a separator, which can be any token
|
||||
except `+` or `*`.
|
||||
|
@ -244,9 +244,9 @@ int main() {
|
|||
```
|
||||
|
||||
After expansion we have `5 * 2 + 3`, and multiplication has greater precedence
|
||||
than addition. If you've used C macros a lot, you probably know the standard
|
||||
than addition. If you’ve used C macros a lot, you probably know the standard
|
||||
idioms for avoiding this problem, as well as five or six others. In Rust, we
|
||||
don't have to worry about it.
|
||||
don’t have to worry about it.
|
||||
|
||||
```rust
|
||||
macro_rules! five_times {
|
||||
|
@ -261,8 +261,8 @@ fn main() {
|
|||
The metavariable `$x` is parsed as a single expression node, and keeps its
|
||||
place in the syntax tree even after substitution.
|
||||
|
||||
Another common problem in macro systems is *variable capture*. Here's a C
|
||||
macro, using [a GNU C extension] to emulate Rust's expression blocks.
|
||||
Another common problem in macro systems is ‘variable capture’. Here’s a C
|
||||
macro, using [a GNU C extension] to emulate Rust’s expression blocks.
|
||||
|
||||
[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
|
||||
|
||||
|
@ -275,7 +275,7 @@ macro, using [a GNU C extension] to emulate Rust's expression blocks.
|
|||
})
|
||||
```
|
||||
|
||||
Here's a simple use case that goes terribly wrong:
|
||||
Here’s a simple use case that goes terribly wrong:
|
||||
|
||||
```text
|
||||
const char *state = "reticulating splines";
|
||||
|
@ -315,10 +315,10 @@ fn main() {
|
|||
```
|
||||
|
||||
This works because Rust has a [hygienic macro system][]. Each macro expansion
|
||||
happens in a distinct *syntax context*, and each variable is tagged with the
|
||||
syntax context where it was introduced. It's as though the variable `state`
|
||||
happens in a distinct ‘syntax context’, and each variable is tagged with the
|
||||
syntax context where it was introduced. It’s as though the variable `state`
|
||||
inside `main` is painted a different "color" from the variable `state` inside
|
||||
the macro, and therefore they don't conflict.
|
||||
the macro, and therefore they don’t conflict.
|
||||
|
||||
[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro
|
||||
|
||||
|
@ -336,7 +336,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Instead you need to pass the variable name into the invocation, so it's tagged
|
||||
Instead you need to pass the variable name into the invocation, so it’s tagged
|
||||
with the right syntax context.
|
||||
|
||||
```rust
|
||||
|
@ -368,7 +368,7 @@ fn main() {
|
|||
|
||||
# Recursive macros
|
||||
|
||||
A macro's expansion can include more macro invocations, including invocations
|
||||
A macro’s expansion can include more macro invocations, including invocations
|
||||
of the very same macro being expanded. These recursive macros are useful for
|
||||
processing tree-structured input, as illustrated by this (simplistic) HTML
|
||||
shorthand:
|
||||
|
@ -429,7 +429,7 @@ they are unstable and require feature gates.
|
|||
Even when Rust code contains un-expanded macros, it can be parsed as a full
|
||||
[syntax tree][ast]. This property can be very useful for editors and other
|
||||
tools that process code. It also has a few consequences for the design of
|
||||
Rust's macro system.
|
||||
Rust’s macro system.
|
||||
|
||||
[ast]: glossary.html#abstract-syntax-tree
|
||||
|
||||
|
@ -454,13 +454,13 @@ consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces
|
|||
must be balanced within a macro invocation. For example, `foo!([)` is
|
||||
forbidden. This allows Rust to know where the macro invocation ends.
|
||||
|
||||
More formally, the macro invocation body must be a sequence of *token trees*.
|
||||
More formally, the macro invocation body must be a sequence of ‘token trees’.
|
||||
A token tree is defined recursively as either
|
||||
|
||||
* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or
|
||||
* any other single token.
|
||||
|
||||
Within a matcher, each metavariable has a *fragment specifier*, identifying
|
||||
Within a matcher, each metavariable has a ‘fragment specifier’, identifying
|
||||
which syntactic form it matches.
|
||||
|
||||
* `ident`: an identifier. Examples: `x`; `foo`.
|
||||
|
@ -482,7 +482,7 @@ There are additional rules regarding the next token after a metavariable:
|
|||
* `pat` variables must be followed by one of: `=> , =`
|
||||
* Other variables may be followed by any token.
|
||||
|
||||
These rules provide some flexibility for Rust's syntax to evolve without
|
||||
These rules provide some flexibility for Rust’s syntax to evolve without
|
||||
breaking existing macros.
|
||||
|
||||
The macro system does not deal with parse ambiguity at all. For example, the
|
||||
|
@ -500,7 +500,7 @@ One downside is that scoping works differently for macros, compared to other
|
|||
constructs in the language.
|
||||
|
||||
Definition and expansion of macros both happen in a single depth-first,
|
||||
lexical-order traversal of a crate's source. So a macro defined at module scope
|
||||
lexical-order traversal of a crate’s source. So a macro defined at module scope
|
||||
is visible to any subsequent code in the same module, which includes the body
|
||||
of any subsequent child `mod` items.
|
||||
|
||||
|
@ -508,8 +508,8 @@ A macro defined within the body of a single `fn`, or anywhere else not at
|
|||
module scope, is visible only within that item.
|
||||
|
||||
If a module has the `macro_use` attribute, its macros are also visible in its
|
||||
parent module after the child's `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent's `mod`
|
||||
parent module after the child’s `mod` item. If the parent also has `macro_use`
|
||||
then the macros will be visible in the grandparent after the parent’s `mod`
|
||||
item, and so forth.
|
||||
|
||||
The `macro_use` attribute can also appear on `extern crate`. In this context
|
||||
|
@ -524,7 +524,7 @@ If the attribute is given simply as `#[macro_use]`, all macros are loaded. If
|
|||
there is no `#[macro_use]` attribute then no macros are loaded. Only macros
|
||||
defined with the `#[macro_export]` attribute may be loaded.
|
||||
|
||||
To load a crate's macros *without* linking it into the output, use `#[no_link]`
|
||||
To load a crate’s macros without linking it into the output, use `#[no_link]`
|
||||
as well.
|
||||
|
||||
An example:
|
||||
|
@ -619,12 +619,12 @@ only appear at the root of your crate, not inside `mod`. This ensures that
|
|||
|
||||
The introductory chapter mentioned recursive macros, but it did not give the
|
||||
full story. Recursive macros are useful for another reason: Each recursive
|
||||
invocation gives you another opportunity to pattern-match the macro's
|
||||
invocation gives you another opportunity to pattern-match the macro’s
|
||||
arguments.
|
||||
|
||||
As an extreme example, it is possible, though hardly advisable, to implement
|
||||
the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
|
||||
within Rust's macro system.
|
||||
within Rust’s macro system.
|
||||
|
||||
```rust
|
||||
macro_rules! bct {
|
||||
|
@ -765,9 +765,9 @@ as `unimplemented!` until you’re ready to write them.
|
|||
|
||||
# Procedural macros
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
If Rust’s macro system can’t do what you need, you may want to write a
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and bugs can be much harder to track down. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
extension plugins are sometimes called *procedural macros* for this reason.
|
||||
extension plugins are sometimes called ‘procedural macros’ for this reason.
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
% Trait Objects
|
||||
|
||||
When code involves polymorphism, there needs to be a mechanism to determine
|
||||
which specific version is actually run. This is called 'dispatch.' There are
|
||||
which specific version is actually run. This is called ‘dispatch’. There are
|
||||
two major forms of dispatch: static dispatch and dynamic dispatch. While Rust
|
||||
favors static dispatch, it also supports dynamic dispatch through a mechanism
|
||||
called 'trait objects.'
|
||||
called ‘trait objects’.
|
||||
|
||||
## Background
|
||||
|
||||
For the rest of this chapter, we'll need a trait and some implementations.
|
||||
Let's make a simple one, `Foo`. It has one method that is expected to return a
|
||||
For the rest of this chapter, we’ll need a trait and some implementations.
|
||||
Let’s make a simple one, `Foo`. It has one method that is expected to return a
|
||||
`String`.
|
||||
|
||||
```rust
|
||||
|
@ -18,7 +18,7 @@ trait Foo {
|
|||
}
|
||||
```
|
||||
|
||||
We'll also implement this trait for `u8` and `String`:
|
||||
We’ll also implement this trait for `u8` and `String`:
|
||||
|
||||
```rust
|
||||
# trait Foo { fn method(&self) -> String; }
|
||||
|
@ -53,7 +53,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Rust uses 'monomorphization' to perform static dispatch here. This means that
|
||||
Rust uses ‘monomorphization’ to perform static dispatch here. This means that
|
||||
Rust will create a special version of `do_something()` for both `u8` and
|
||||
`String`, and then replace the call sites with calls to these specialized
|
||||
functions. In other words, Rust generates something like this:
|
||||
|
@ -82,7 +82,7 @@ fn main() {
|
|||
This has a great upside: static dispatch allows function calls to be
|
||||
inlined because the callee is known at compile time, and inlining is
|
||||
the key to good optimization. Static dispatch is fast, but it comes at
|
||||
a tradeoff: 'code bloat', due to many copies of the same function
|
||||
a tradeoff: ‘code bloat’, due to many copies of the same function
|
||||
existing in the binary, one for each type.
|
||||
|
||||
Furthermore, compilers aren’t perfect and may “optimize” code to become slower.
|
||||
|
@ -99,7 +99,7 @@ reason.
|
|||
|
||||
## Dynamic dispatch
|
||||
|
||||
Rust provides dynamic dispatch through a feature called 'trait objects.' Trait
|
||||
Rust provides dynamic dispatch through a feature called ‘trait objects’. Trait
|
||||
objects, like `&Foo` or `Box<Foo>`, are normal values that store a value of
|
||||
*any* type that implements the given trait, where the precise type can only be
|
||||
known at runtime.
|
||||
|
@ -109,12 +109,12 @@ implements the trait by *casting* it (e.g. `&x as &Foo`) or *coercing* it
|
|||
(e.g. using `&x` as an argument to a function that takes `&Foo`).
|
||||
|
||||
These trait object coercions and casts also work for pointers like `&mut T` to
|
||||
`&mut Foo` and `Box<T>` to `Box<Foo>`, but that's all at the moment. Coercions
|
||||
`&mut Foo` and `Box<T>` to `Box<Foo>`, but that’s all at the moment. Coercions
|
||||
and casts are identical.
|
||||
|
||||
This operation can be seen as "erasing" the compiler's knowledge about the
|
||||
This operation can be seen as ‘erasing’ the compiler’s knowledge about the
|
||||
specific type of the pointer, and hence trait objects are sometimes referred to
|
||||
as "type erasure".
|
||||
as ‘type erasure’.
|
||||
|
||||
Coming back to the example above, we can use the same trait to perform dynamic
|
||||
dispatch with trait objects by casting:
|
||||
|
@ -167,7 +167,7 @@ on the heap to store it.
|
|||
|
||||
For `Foo`, we would need to have a value that could be at least either a
|
||||
`String` (24 bytes) or a `u8` (1 byte), as well as any other type for which
|
||||
dependent crates may implement `Foo` (any number of bytes at all). There's no
|
||||
dependent crates may implement `Foo` (any number of bytes at all). There’s no
|
||||
way to guarantee that this last point can work if the values are stored without
|
||||
a pointer, because those other types can be arbitrarily large.
|
||||
|
||||
|
@ -177,14 +177,14 @@ when we are tossing a trait object around, only the size of the pointer itself.
|
|||
### Representation
|
||||
|
||||
The methods of the trait can be called on a trait object via a special record
|
||||
of function pointers traditionally called a 'vtable' (created and managed by
|
||||
of function pointers traditionally called a ‘vtable’ (created and managed by
|
||||
the compiler).
|
||||
|
||||
Trait objects are both simple and complicated: their core representation and
|
||||
layout is quite straight-forward, but there are some curly error messages and
|
||||
surprising behaviors to discover.
|
||||
|
||||
Let's start simple, with the runtime representation of a trait object. The
|
||||
Let’s start simple, with the runtime representation of a trait object. The
|
||||
`std::raw` module contains structs with layouts that are the same as the
|
||||
complicated built-in types, [including trait objects][stdraw]:
|
||||
|
||||
|
@ -199,12 +199,12 @@ pub struct TraitObject {
|
|||
|
||||
[stdraw]: ../std/raw/struct.TraitObject.html
|
||||
|
||||
That is, a trait object like `&Foo` consists of a "data" pointer and a "vtable"
|
||||
That is, a trait object like `&Foo` consists of a ‘data’ pointer and a ‘vtable’
|
||||
pointer.
|
||||
|
||||
The data pointer addresses the data (of some unknown type `T`) that the trait
|
||||
object is storing, and the vtable pointer points to the vtable ("virtual method
|
||||
table") corresponding to the implementation of `Foo` for `T`.
|
||||
object is storing, and the vtable pointer points to the vtable (‘virtual method
|
||||
table’) corresponding to the implementation of `Foo` for `T`.
|
||||
|
||||
|
||||
A vtable is essentially a struct of function pointers, pointing to the concrete
|
||||
|
@ -212,7 +212,7 @@ piece of machine code for each method in the implementation. A method call like
|
|||
`trait_object.method()` will retrieve the correct pointer out of the vtable and
|
||||
then do a dynamic call of it. For example:
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
struct FooVtable {
|
||||
destructor: fn(*mut ()),
|
||||
size: usize,
|
||||
|
@ -261,7 +261,7 @@ static Foo_for_String_vtable: FooVtable = FooVtable {
|
|||
```
|
||||
|
||||
The `destructor` field in each vtable points to a function that will clean up
|
||||
any resources of the vtable's type, for `u8` it is trivial, but for `String` it
|
||||
any resources of the vtable’s type, for `u8` it is trivial, but for `String` it
|
||||
will free the memory. This is necessary for owning trait objects like
|
||||
`Box<Foo>`, which need to clean-up both the `Box` allocation as well as the
|
||||
internal type when they go out of scope. The `size` and `align` fields store
|
||||
|
@ -270,11 +270,11 @@ essentially unused at the moment since the information is embedded in the
|
|||
destructor, but will be used in the future, as trait objects are progressively
|
||||
made more flexible.
|
||||
|
||||
Suppose we've got some values that implement `Foo`, then the explicit form of
|
||||
Suppose we’ve got some values that implement `Foo`, then the explicit form of
|
||||
construction and use of `Foo` trait objects might look a bit like (ignoring the
|
||||
type mismatches: they're all just pointers anyway):
|
||||
type mismatches: they’re all just pointers anyway):
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
let a: String = "foo".to_string();
|
||||
let x: u8 = 1;
|
||||
|
||||
|
|
Loading…
Reference in a new issue