Skip to content

Commit 9974465

Browse files
committed
get over bold text madness, changes per PR, brought the "returning pointers" section back to pointers guide
1 parent 64dad2c commit 9974465

File tree

2 files changed

+67
-26
lines changed

2 files changed

+67
-26
lines changed

src/doc/guide-lifetimes.md

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,11 @@ let on_the_heap : Box<Point> = box Point {x: 7.0, y: 9.0};
4545

4646
Suppose we wanted to write a procedure that computed the distance between any
4747
two points, no matter where they were stored. One option is to define a function
48-
that takes two arguments of type `Point`—that is, it takes the points __by value__.
49-
But if we define it this way, calling the function will cause the points __to be
50-
copied__. For points, this is probably not so bad, but often copies are
51-
expensive. Worse, if the data type contains mutable fields, copying can change
52-
the semantics of your program in unexpected ways. So we'd like to define
53-
a function that takes the points just as a __reference__/__borrowed pointer__.
48+
that takes two arguments of type `Point`—that is, it takes the points by value.
49+
But if we define it this way, calling the function will cause the points to be
50+
copied. For points, this is probably not so bad, but often copies are
51+
expensive. So we'd like to define a function that takes the points just as
52+
a reference.
5453

5554
~~~
5655
# struct Point {x: f64, y: f64}
@@ -62,27 +61,26 @@ fn compute_distance(p1: &Point, p2: &Point) -> f64 {
6261
}
6362
~~~
6463

65-
Now we can call `compute_distance()`
64+
Now we can call `compute_distance()`:
6665

6766
~~~
6867
# struct Point {x: f64, y: f64}
6968
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
7069
# let on_the_heap : Box<Point> = box Point{x: 7.0, y: 9.0};
7170
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
72-
compute_distance(&on_the_stack, on_the_heap);
71+
compute_distance(&on_the_stack, &*on_the_heap);
7372
~~~
7473

7574
Here, the `&` operator takes the address of the variable
7675
`on_the_stack`; this is because `on_the_stack` has the type `Point`
7776
(that is, a struct value) and we have to take its address to get a
7877
value. We also call this _borrowing_ the local variable
79-
`on_the_stack`, because we have created __an alias__: that is, another
78+
`on_the_stack`, because we have created an alias: that is, another
8079
name for the same data.
8180

82-
In contrast, we can pass `on_the_heap` to `compute_distance` directly.
83-
The compiler automatically converts a box like `Box<Point>` to a reference like
84-
`&Point`. This is another form of borrowing: in this case, the caller lends
85-
the contents of the box to the callee.
81+
For the second argument, we need to grab the contents of `on_the_heap`
82+
by using the `*` operator, and then get a reference to that data. In
83+
order to convert `Box<T>` into a `&T`, we need to use `&*`.
8684

8785
Whenever a caller lends data to a callee, there are some limitations on what
8886
the caller can do with the original. For example, if the contents of a
@@ -166,12 +164,12 @@ as well as from the owned box, and then compute the distance between them.
166164

167165
# Lifetimes
168166

169-
We’ve seen a few examples of borrowing data. Up till this point, we’ve glossed
167+
We’ve seen a few examples of borrowing data. To this point, we’ve glossed
170168
over issues of safety. As stated in the introduction, at runtime a reference
171169
is simply a pointer, nothing more. Therefore, avoiding C's problems with
172170
dangling pointers requires a compile-time safety check.
173171

174-
The basis for the check is the notion of __lifetimes__. A lifetime is a
172+
The basis for the check is the notion of _lifetimes_. A lifetime is a
175173
static approximation of the span of execution during which the pointer
176174
is valid: it always corresponds to some expression or block within the
177175
program.
@@ -324,7 +322,7 @@ circle constant][tau] and not that dreadfully outdated notion of pi).
324322

325323
The second match is more interesting. Here we match against a
326324
rectangle and extract its size: but rather than copy the `size`
327-
struct, we use a __by-reference binding__ to create a pointer to it. In
325+
struct, we use a by-reference binding to create a pointer to it. In
328326
other words, a pattern binding like `ref size` binds the name `size`
329327
to a pointer of type `&size` into the _interior of the enum_.
330328

src/doc/guide-pointers.md

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ error: mismatched types: expected `&int` but found `<generic integer #0>` (expec
3737

3838
What gives? It needs a pointer! Therefore I have to use pointers!"
3939

40-
Turns out, you don't. __All you need is a reference__. Try this on for size:
40+
Turns out, you don't. All you need is a reference. Try this on for size:
4141

4242
~~~rust
4343
# fn succ(x: &int) -> int { *x + 1 }
@@ -74,8 +74,7 @@ Here are the use-cases for pointers. I've prefixed them with the name of the
7474
pointer that satisfies that use-case:
7575

7676
1. Owned: `Box<Trait>` must be a pointer, because you don't know the size of the
77-
object, so indirection is mandatory. Notation might change once Rust
78-
support DST fully so we recommend you stay tuned.
77+
object, so indirection is mandatory.
7978

8079
2. Owned: You need a recursive data structure. These can be infinite sized, so
8180
indirection is mandatory.
@@ -89,7 +88,10 @@ common, such as C++, please read "A note..." below.
8988
care about its ownership. If you make the argument a reference, callers
9089
can send in whatever kind they want.
9190

92-
Four exceptions. That's it. Otherwise, you shouldn't need them. Be sceptical
91+
5. Shared: You need to share data among tasks. You can achieve that via the
92+
`Rc` and `Arc` types.
93+
94+
Five exceptions. That's it. Otherwise, you shouldn't need them. Be sceptical
9395
of pointers in Rust: use them for a deliberate purpose, not just to make the
9496
compiler happy.
9597

@@ -205,10 +207,6 @@ The inner lists _must_ be an owned pointer, because we can't know how many
205207
elements are in the list. Without knowing the length, we don't know the size,
206208
and therefore require the indirection that pointers offer.
207209

208-
> Note: Nil is just part of the List enum and even though is being used
209-
> to represent the concept of "nothing", you shouldn't think of it as
210-
> NULL. Rust doesn't have NULL.
211-
212210
## Efficiency
213211

214212
This should almost never be a concern, but because creating an owned pointer
@@ -284,8 +282,8 @@ fn main() {
284282
~~~
285283

286284
This prints `5.83095189`. You can see that the `compute_distance` function
287-
takes in two references, but we give it a stack allocated reference and an
288-
owned box reference.
285+
takes in two references, a reference to a value on the stack, and a reference
286+
to a value in a box.
289287
Of course, if this were a real program, we wouldn't have any of these pointers,
290288
they're just there to demonstrate the concepts.
291289

@@ -361,6 +359,51 @@ hard for a computer, too! There is an entire [guide devoted to references
361359
and lifetimes](guide-lifetimes.html) that goes into lifetimes in
362360
great detail, so if you want the full details, check that out.
363361

362+
# Returning Pointers
363+
364+
We've talked a lot about functions that accept various kinds of pointers, but
365+
what about returning them? In general, it is better to let the caller decide
366+
how to use a function's output, instead of assuming a certain type of pointer
367+
is best.
368+
369+
What does that mean? Don't do this:
370+
371+
~~~rust
372+
fn foo(x: Box<int>) -> Box<int> {
373+
return box *x;
374+
}
375+
376+
fn main() {
377+
let x = box 5;
378+
let y = foo(x);
379+
}
380+
~~~
381+
382+
Do this:
383+
384+
~~~rust
385+
fn foo(x: Box<int>) -> int {
386+
return *x;
387+
}
388+
389+
fn main() {
390+
let x = box 5;
391+
let y = box foo(x);
392+
}
393+
~~~
394+
395+
This gives you flexibility, without sacrificing performance.
396+
397+
You may think that this gives us terrible performance: return a value and then
398+
immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
399+
than that. There is no copy in this code. `main` allocates enough room for the
400+
`box int`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
401+
the value straight into that pointer. This writes the return value directly into
402+
the allocated box.
403+
404+
This is important enough that it bears repeating: pointers are not for optimizing
405+
returning values from your code. Allow the caller to choose how they want to
406+
use your output.
364407

365408
# Related Resources
366409

0 commit comments

Comments
 (0)