1 # SOME DESCRIPTIVE TITLE
2 # Copyright (C) YEAR The Rust Project Developers
3 # This file is distributed under the same license as the Rust package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
9 "Project-Id-Version: Rust 0.8\n"
10 "POT-Creation-Date: 2013-07-22 23:37+0900\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
20 #: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
21 #: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4
22 #: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4
23 msgid "# Introduction"
27 #: doc/tutorial.md:1108 doc/tutorial-borrowed-ptr.md:72
28 msgid "Now we can call `compute_distance()` in various ways:"
32 #: doc/tutorial-borrowed-ptr.md:2
33 msgid "% Rust Borrowed Pointers Tutorial"
37 #: doc/tutorial-borrowed-ptr.md:14
39 "Borrowed pointers are one of the more flexible and powerful tools available "
40 "in Rust. A borrowed pointer can point anywhere: into the managed or exchange "
41 "heap, into the stack, and even into the interior of another data structure. "
42 "A borrowed pointer is as flexible as a C pointer or C++ reference. However, "
43 "unlike C and C++ compilers, the Rust compiler includes special static checks "
44 "that ensure that programs use borrowed pointers safely. Another advantage of "
45 "borrowed pointers is that they are invisible to the garbage collector, so "
46 "working with borrowed pointers helps reduce the overhead of automatic memory "
51 #: doc/tutorial-borrowed-ptr.md:18
53 "Despite their complete safety, a borrowed pointer's representation at "
54 "runtime is the same as that of an ordinary pointer in a C program. They "
55 "introduce zero overhead. The compiler does all safety checks at compile time."
59 #: doc/tutorial-borrowed-ptr.md:24
61 "Although borrowed pointers have rather elaborate theoretical underpinnings "
62 "(region pointers), the core concepts will be familiar to anyone who has "
63 "worked with C or C++. Therefore, the best way to explain how they are used—"
64 "and their limitations—is probably just to work through several examples."
68 #: doc/tutorial-borrowed-ptr.md:26
73 #: doc/tutorial-borrowed-ptr.md:31
75 "Borrowed pointers are called *borrowed* because they are only valid for a "
76 "limited duration. Borrowed pointers never claim any kind of ownership over "
77 "the data that they point to: instead, they are used for cases where you "
78 "would like to use data for a short time."
82 #: doc/tutorial-borrowed-ptr.md:33
83 msgid "As an example, consider a simple struct type `Point`:"
87 #: doc/tutorial-borrowed-ptr.md:37
88 msgid "~~~ struct Point {x: float, y: float} ~~~"
92 #: doc/tutorial-borrowed-ptr.md:41
94 "We can use this simple definition to allocate points in many different ways. "
95 "For example, in this code, each of these three local variables contains a "
96 "point, but allocated in a different place:"
100 #: doc/tutorial-borrowed-ptr.md:48
104 "# struct Point {x: float, y: float}\n"
105 "let on_the_stack : Point = Point {x: 3.0, y: 4.0};\n"
106 "let managed_box : @Point = @Point {x: 5.0, y: 1.0};\n"
107 "let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};\n"
112 #: doc/tutorial-borrowed-ptr.md:60
114 "Suppose we wanted to write a procedure that computed the distance between "
115 "any two points, no matter where they were stored. For example, we might like "
116 "to compute the distance between `on_the_stack` and `managed_box`, or between "
117 "`managed_box` and `owned_box`. One option is to define a function that takes "
118 "two arguments of type `Point`—that is, it takes the points by value. But if "
119 "we define it this way, calling the function will cause the points to be "
120 "copied. For points, this is probably not so bad, but often copies are "
121 "expensive. Worse, if the data type contains mutable fields, copying can "
122 "change the semantics of your program in unexpected ways. So we'd like to "
123 "define a function that takes the points by pointer. We can use borrowed "
124 "pointers to do this:"
128 #: doc/tutorial-borrowed-ptr.md:70
132 "# struct Point {x: float, y: float}\n"
133 "# fn sqrt(f: float) -> float { 0f }\n"
134 "fn compute_distance(p1: &Point, p2: &Point) -> float {\n"
135 " let x_d = p1.x - p2.x;\n"
136 " let y_d = p1.y - p2.y;\n"
137 " sqrt(x_d * x_d + y_d * y_d)\n"
143 #: doc/tutorial-borrowed-ptr.md:82
147 "# struct Point {x: float, y: float}\n"
148 "# let on_the_stack : Point = Point{x: 3.0, y: 4.0};\n"
149 "# let managed_box : @Point = @Point{x: 5.0, y: 1.0};\n"
150 "# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};\n"
151 "# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }\n"
152 "compute_distance(&on_the_stack, managed_box);\n"
153 "compute_distance(managed_box, owned_box);\n"
158 #: doc/tutorial-borrowed-ptr.md:89
160 "Here, the `&` operator takes the address of the variable `on_the_stack`; "
161 "this is because `on_the_stack` has the type `Point` (that is, a struct "
162 "value) and we have to take its address to get a value. We also call this "
163 "_borrowing_ the local variable `on_the_stack`, because we have created an "
164 "alias: that is, another name for the same data."
168 #: doc/tutorial-borrowed-ptr.md:95
170 "In contrast, we can pass the boxes `managed_box` and `owned_box` to "
171 "`compute_distance` directly. The compiler automatically converts a box like "
172 "`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another "
173 "form of borrowing: in this case, the caller lends the contents of the "
174 "managed or owned box to the callee."
178 #: doc/tutorial-borrowed-ptr.md:105
180 "Whenever a caller lends data to a callee, there are some limitations on what "
181 "the caller can do with the original. For example, if the contents of a "
182 "variable have been lent out, you cannot send that variable to another task. "
183 "In addition, the compiler will reject any code that might cause the borrowed "
184 "value to be freed or overwrite its component fields with values of different "
185 "types (I'll get into what kinds of actions those are shortly). This rule "
186 "should make intuitive sense: you must wait for a borrower to return the "
187 "value that you lent it (that is, wait for the borrowed pointer to go out of "
188 "scope) before you can make full use of it again."
192 #: doc/tutorial-borrowed-ptr.md:107
193 msgid "# Other uses for the & operator"
197 #: doc/tutorial-borrowed-ptr.md:109
198 msgid "In the previous example, the value `on_the_stack` was defined like so:"
202 #: doc/tutorial-borrowed-ptr.md:114
204 "~~~ # struct Point {x: float, y: float} let on_the_stack: Point = Point {x: "
209 #: doc/tutorial-borrowed-ptr.md:119
211 "This declaration means that code can only pass `Point` by value to other "
212 "functions. As a consequence, we had to explicitly take the address of "
213 "`on_the_stack` to get a borrowed pointer. Sometimes however it is more "
214 "convenient to move the & operator into the definition of `on_the_stack`:"
218 #: doc/tutorial-borrowed-ptr.md:124
220 "~~~ # struct Point {x: float, y: float} let on_the_stack2: &Point = &Point "
221 "{x: 3.0, y: 4.0}; ~~~"
225 #: doc/tutorial-borrowed-ptr.md:128
227 "Applying `&` to an rvalue (non-assignable location) is just a convenient "
228 "shorthand for creating a temporary and taking its address. A more verbose "
229 "way to write the same code is:"
233 #: doc/tutorial-borrowed-ptr.md:134
235 "~~~ # struct Point {x: float, y: float} let tmp = Point {x: 3.0, y: 4.0}; "
236 "let on_the_stack2 : &Point = &tmp; ~~~"
240 #: doc/tutorial-borrowed-ptr.md:136
241 msgid "# Taking the address of fields"
245 #: doc/tutorial-borrowed-ptr.md:141
247 "As in C, the `&` operator is not limited to taking the address of local "
248 "variables. It can also take the address of fields or individual array "
249 "elements. For example, consider this type definition for `rectangle`:"
253 #: doc/tutorial-borrowed-ptr.md:147
255 "~~~ struct Point {x: float, y: float} // as before struct Size {w: float, h: "
256 "float} // as before struct Rectangle {origin: Point, size: Size} ~~~"
260 #: doc/tutorial-borrowed-ptr.md:149
261 msgid "Now, as before, we can define rectangles in a few different ways:"
265 #: doc/tutorial-borrowed-ptr.md:161
269 "# struct Point {x: float, y: float}\n"
270 "# struct Size {w: float, h: float} // as before\n"
271 "# struct Rectangle {origin: Point, size: Size}\n"
272 "let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f},\n"
273 " size: Size {w: 3f, h: 4f}};\n"
274 "let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},\n"
275 " size: Size {w: 3f, h: 4f}};\n"
276 "let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f},\n"
277 " size: Size {w: 3f, h: 4f}};\n"
282 #: doc/tutorial-borrowed-ptr.md:164
284 "In each case, we can extract out individual subcomponents with the `&` "
285 "operator. For example, I could write:"
289 #: doc/tutorial-borrowed-ptr.md:175
291 "~~~ # struct Point {x: float, y: float} // as before # struct Size {w: "
292 "float, h: float} // as before # struct Rectangle {origin: Point, size: Size} "
293 "# let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f}, size: Size {w: "
294 "3f, h: 4f}}; # let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f}, "
295 "size: Size {w: 3f, h: 4f}}; # let rect_owned = ~Rectangle {origin: Point {x: "
296 "5f, y: 6f}, size: Size {w: 3f, h: 4f}}; # fn compute_distance(p1: &Point, "
297 "p2: &Point) -> float { 0f } compute_distance(&rect_stack.origin, "
298 "&rect_managed.origin); ~~~"
302 #: doc/tutorial-borrowed-ptr.md:178
304 "which would borrow the field `origin` from the rectangle on the stack as "
305 "well as from the managed box, and then compute the distance between them."
309 #: doc/tutorial-borrowed-ptr.md:180
310 msgid "# Borrowing managed boxes and rooting"
314 #: doc/tutorial-borrowed-ptr.md:186
316 "We’ve seen a few examples so far of borrowing heap boxes, both managed and "
317 "owned. Up till this point, we’ve glossed over issues of safety. As stated in "
318 "the introduction, at runtime a borrowed pointer is simply a pointer, nothing "
319 "more. Therefore, avoiding C's problems with dangling pointers requires a "
320 "compile-time safety check."
324 #: doc/tutorial-borrowed-ptr.md:197
326 "The basis for the check is the notion of _lifetimes_. A lifetime is a static "
327 "approximation of the span of execution during which the pointer is valid: it "
328 "always corresponds to some expression or block within the program. Code "
329 "inside that expression can use the pointer without restrictions. But if the "
330 "pointer escapes from that expression (for example, if the expression "
331 "contains an assignment expression that assigns the pointer to a mutable "
332 "field of a data structure with a broader scope than the pointer itself), the "
333 "compiler reports an error. We'll be discussing lifetimes more in the "
334 "examples to come, and a more thorough introduction is also available."
338 #: doc/tutorial-borrowed-ptr.md:202
340 "When the `&` operator creates a borrowed pointer, the compiler must ensure "
341 "that the pointer remains valid for its entire lifetime. Sometimes this is "
342 "relatively easy, such as when taking the address of a local variable or a "
343 "field that is stored on the stack:"
347 #: doc/tutorial-borrowed-ptr.md:211
351 "struct X { f: int }\n"
353 " let mut x = X { f: 3 };\n"
354 " let y = &mut x.f; // -+ L\n"
361 #: doc/tutorial-borrowed-ptr.md:216
363 "Here, the lifetime of the borrowed pointer `y` is simply L, the remainder of "
364 "the function body. The compiler need not do any other work to prove that "
365 "code will not free `x.f`. This is true even if the code mutates `x`."
369 #: doc/tutorial-borrowed-ptr.md:218
370 msgid "The situation gets more complex when borrowing data inside heap boxes:"
374 #: doc/tutorial-borrowed-ptr.md:227
378 "# struct X { f: int }\n"
380 " let mut x = @X { f: 3 };\n"
381 " let y = &x.f; // -+ L\n"
388 #: doc/tutorial-borrowed-ptr.md:238
390 "In this example, the value `x` is a heap box, and `y` is therefore a pointer "
391 "into that heap box. Again the lifetime of `y` is L, the remainder of the "
392 "function body. But there is a crucial difference: suppose `x` were to be "
393 "reassigned during the lifetime L? If the compiler isn't careful, the managed "
394 "box could become *unrooted*, and would therefore be subject to garbage "
395 "collection. A heap box that is unrooted is one such that no pointer values "
396 "in the heap point to it. It would violate memory safety for the box that was "
397 "originally assigned to `x` to be garbage-collected, since a non-heap pointer "
398 "*`y`* still points into it."
402 #: doc/tutorial-borrowed-ptr.md:241
404 "> ***Note:*** Our current implementation implements the garbage collector > "
405 "using reference counting and cycle detection."
409 #: doc/tutorial-borrowed-ptr.md:247
411 "For this reason, whenever an `&` expression borrows the interior of a "
412 "managed box stored in a mutable location, the compiler inserts a temporary "
413 "that ensures that the managed box remains live for the entire lifetime. So, "
414 "the above example would be compiled as if it were written"
418 #: doc/tutorial-borrowed-ptr.md:257
422 "# struct X { f: int }\n"
424 " let mut x = @X {f: 3};\n"
426 " let y = &x1.f; // -+ L\n"
433 #: doc/tutorial-borrowed-ptr.md:260
435 "Now if `x` is reassigned, the pointer `y` will still remain valid. This "
436 "process is called *rooting*."
440 #: doc/tutorial-borrowed-ptr.md:262
441 msgid "# Borrowing owned boxes"
445 #: doc/tutorial-borrowed-ptr.md:268
447 "The previous example demonstrated *rooting*, the process by which the "
448 "compiler ensures that managed boxes remain live for the duration of a "
449 "borrow. Unfortunately, rooting does not work for borrows of owned boxes, "
450 "because it is not possible to have two references to a owned box."
454 #: doc/tutorial-borrowed-ptr.md:274
456 "For owned boxes, therefore, the compiler will only allow a borrow *if the "
457 "compiler can guarantee that the owned box will not be reassigned or moved "
458 "for the lifetime of the pointer*. This does not necessarily mean that the "
459 "owned box is stored in immutable memory. For example, the following function "
464 #: doc/tutorial-borrowed-ptr.md:289
468 "# fn some_condition() -> bool { true }\n"
469 "# struct Foo { f: int }\n"
470 "fn example3() -> int {\n"
471 " let mut x = ~Foo {f: 3};\n"
472 " if some_condition() {\n"
473 " let y = &x.f; // -+ L\n"
476 " x = ~Foo {f: 4};\n"
484 #: doc/tutorial-borrowed-ptr.md:295
486 "Here, as before, the interior of the variable `x` is being borrowed and `x` "
487 "is declared as mutable. However, the compiler can prove that `x` is not "
488 "assigned anywhere in the lifetime L of the variable `y`. Therefore, it "
489 "accepts the function, even though `x` is mutable and in fact is mutated "
490 "later in the function."
494 #: doc/tutorial-borrowed-ptr.md:301
496 "It may not be clear why we are so concerned about mutating a borrowed "
497 "variable. The reason is that the runtime system frees any owned box _as soon "
498 "as its owning reference changes or goes out of scope_. Therefore, a program "
499 "like this is illegal (and would be rejected by the compiler):"
503 #: doc/tutorial-borrowed-ptr.md:310
506 "~~~ {.xfail-test}\n"
507 "fn example3() -> int {\n"
508 " let mut x = ~X {f: 3};\n"
510 " x = ~X {f: 4}; // Error reported here.\n"
517 #: doc/tutorial-borrowed-ptr.md:313
519 "To make this clearer, consider this diagram showing the state of memory "
520 "immediately before the re-assignment of `x`:"
524 #: doc/tutorial-borrowed-ptr.md:316 doc/tutorial-borrowed-ptr.md:330
528 " Stack Exchange Heap\n"
532 #: doc/tutorial-borrowed-ptr.md:325
536 " | ~{f:int} | ----+\n"
537 " y +----------+ |\n"
539 " +----------+ | +---------+\n"
546 #: doc/tutorial-borrowed-ptr.md:327
547 msgid "Once the reassignment occurs, the memory will look like this:"
551 #: doc/tutorial-borrowed-ptr.md:339
554 " x +----------+ +---------+\n"
555 " | ~{f:int} | -------> | f: 4 |\n"
556 " y +----------+ +---------+\n"
558 " +----------+ | +---------+\n"
559 " +--> | (freed) |\n"
565 #: doc/tutorial-borrowed-ptr.md:342
567 "Here you can see that the variable `y` still points at the old box, which "
572 #: doc/tutorial-borrowed-ptr.md:348
574 "In fact, the compiler can apply the same kind of reasoning to any memory "
575 "that is _(uniquely) owned by the stack frame_. So we could modify the "
576 "previous example to introduce additional owned pointers and structs, and the "
577 "compiler will still be able to detect possible mutations:"
581 #: doc/tutorial-borrowed-ptr.md:353
584 "~~~ {.xfail-test}\n"
585 "fn example3() -> int {\n"
586 " struct R { g: int }\n"
587 " struct S { f: ~R }\n"
591 #: doc/tutorial-borrowed-ptr.md:361
594 " let mut x = ~S {f: ~R {g: 3}};\n"
596 " x = ~S {f: ~R {g: 4}}; // Error reported here.\n"
597 " x.f = ~R {g: 5}; // Error reported here.\n"
604 #: doc/tutorial-borrowed-ptr.md:365
606 "In this case, two errors are reported, one when the variable `x` is modified "
607 "and another when `x.f` is modified. Either modification would invalidate the "
612 #: doc/tutorial-borrowed-ptr.md:367
613 msgid "# Borrowing and enums"
617 #: doc/tutorial-borrowed-ptr.md:373
619 "The previous example showed that the type system forbids any borrowing of "
620 "owned boxes found in aliasable, mutable memory. This restriction prevents "
621 "pointers from pointing into freed memory. There is one other case where the "
622 "compiler must be very careful to ensure that pointers remain valid: pointers "
623 "into the interior of an `enum`."
627 #: doc/tutorial-borrowed-ptr.md:376
629 "As an example, let’s look at the following `shape` type that can represent "
630 "both rectangles and circles:"
634 #: doc/tutorial-borrowed-ptr.md:385
638 "struct Point {x: float, y: float}; // as before\n"
639 "struct Size {w: float, h: float}; // as before\n"
641 " Circle(Point, float), // origin, radius\n"
642 " Rectangle(Point, Size) // upper-left, dimensions\n"
648 #: doc/tutorial-borrowed-ptr.md:389
650 "Now we might write a function to compute the area of a shape. This function "
651 "takes a borrowed pointer to a shape, to avoid the need for copying."
655 #: doc/tutorial-borrowed-ptr.md:405
659 "# struct Point {x: float, y: float}; // as before\n"
660 "# struct Size {w: float, h: float}; // as before\n"
662 "# Circle(Point, float), // origin, radius\n"
663 "# Rectangle(Point, Size) // upper-left, dimensions\n"
665 "# static tau: float = 6.28f;\n"
666 "fn compute_area(shape: &Shape) -> float {\n"
668 " Circle(_, radius) => 0.5 * tau * radius * radius,\n"
669 " Rectangle(_, ref size) => size.w * size.h\n"
676 #: doc/tutorial-borrowed-ptr.md:410
678 "The first case matches against circles. Here, the pattern extracts the "
679 "radius from the shape variant and the action uses it to compute the area of "
680 "the circle. (Like any up-to-date engineer, we use the [tau circle constant]"
681 "[tau] and not that dreadfully outdated notion of pi)."
685 #: doc/tutorial-borrowed-ptr.md:412
686 msgid "[tau]: http://www.math.utah.edu/~palais/pi.html"
690 #: doc/tutorial-borrowed-ptr.md:418
692 "The second match is more interesting. Here we match against a rectangle and "
693 "extract its size: but rather than copy the `size` struct, we use a by-"
694 "reference binding to create a pointer to it. In other words, a pattern "
695 "binding like `ref size` binds the name `size` to a pointer of type `&size` "
696 "into the _interior of the enum_."
700 #: doc/tutorial-borrowed-ptr.md:421
702 "To make this more clear, let's look at a diagram of memory layout in the "
703 "case where `shape` points at a rectangle:"
707 #: doc/tutorial-borrowed-ptr.md:424 doc/tutorial-borrowed-ptr.md:449
715 #: doc/tutorial-borrowed-ptr.md:433
718 "+-------+ +---------------+\n"
719 "| shape | ------> | rectangle( |\n"
720 "+-------+ | {x: float, |\n"
721 "| size | -+ | y: float}, |\n"
722 "+-------+ +----> | {w: float, |\n"
724 " +---------------+\n"
729 #: doc/tutorial-borrowed-ptr.md:440
731 "Here you can see that rectangular shapes are composed of five words of "
732 "memory. The first is a tag indicating which variant this enum is "
733 "(`rectangle`, in this case). The next two words are the `x` and `y` fields "
734 "for the point and the remaining two are the `w` and `h` fields for the size. "
735 "The binding `size` is then a pointer into the inside of the shape."
739 #: doc/tutorial-borrowed-ptr.md:446
741 "Perhaps you can see where the danger lies: if the shape were somehow to be "
742 "reassigned, perhaps to a circle, then although the memory used to store that "
743 "shape value would still be valid, _it would have a different type_! The "
744 "following diagram shows what memory would look like if code overwrote "
745 "`shape` with a circle:"
749 #: doc/tutorial-borrowed-ptr.md:458
752 "+-------+ +---------------+\n"
753 "| shape | ------> | circle( |\n"
754 "+-------+ | {x: float, |\n"
755 "| size | -+ | y: float}, |\n"
756 "+-------+ +----> | float) |\n"
758 " +---------------+\n"
763 #: doc/tutorial-borrowed-ptr.md:463
765 "As you can see, the `size` pointer would be pointing at a `float` instead of "
766 "a struct. This is not good: dereferencing the second field of a `float` as "
767 "if it were a struct with two fields would be a memory safety violation."
771 #: doc/tutorial-borrowed-ptr.md:475
773 "So, in fact, for every `ref` binding, the compiler will impose the same "
774 "rules as the ones we saw for borrowing the interior of a owned box: it must "
775 "be able to guarantee that the `enum` will not be overwritten for the "
776 "duration of the borrow. In fact, the compiler would accept the example we "
777 "gave earlier. The example is safe because the shape pointer has type "
778 "`&Shape`, which means \"borrowed pointer to immutable memory containing a "
779 "`shape`\". If, however, the type of that pointer were `&mut Shape`, then the "
780 "ref binding would be ill-typed. Just as with owned boxes, the compiler will "
781 "permit `ref` bindings into data owned by the stack frame even if the data "
782 "are mutable, but otherwise it requires that the data reside in immutable "
787 #: doc/tutorial-borrowed-ptr.md:477
788 msgid "# Returning borrowed pointers"
792 #: doc/tutorial-borrowed-ptr.md:483
794 "So far, all of the examples we have looked at, use borrowed pointers in a "
795 "“downward” direction. That is, a method or code block creates a borrowed "
796 "pointer, then uses it within the same scope. It is also possible to return "
797 "borrowed pointers as the result of a function, but as we'll see, doing so "
798 "requires some explicit annotation."
802 #: doc/tutorial-borrowed-ptr.md:485
803 msgid "For example, we could write a subroutine like this:"
807 #: doc/tutorial-borrowed-ptr.md:490
809 "~~~ struct Point {x: float, y: float} fn get_x<'r>(p: &'r Point) -> &'r "
814 #: doc/tutorial-borrowed-ptr.md:498
816 "Here, the function `get_x()` returns a pointer into the structure it was "
817 "given. The type of the parameter (`&'r Point`) and return type (`&'r float`) "
818 "both use a new syntactic form that we have not seen so far. Here the "
819 "identifier `r` names the lifetime of the pointer explicitly. So in effect, "
820 "this function declares that it takes a pointer with lifetime `r` and returns "
821 "a pointer with that same lifetime."
825 #: doc/tutorial-borrowed-ptr.md:504
827 "In general, it is only possible to return borrowed pointers if they are "
828 "derived from a parameter to the procedure. In that case, the pointer result "
829 "will always have the same lifetime as one of the parameters; named lifetimes "
830 "indicate which parameter that is."
834 #: doc/tutorial-borrowed-ptr.md:510
836 "In the previous examples, function parameter types did not include a "
837 "lifetime name. In those examples, the compiler simply creates a fresh name "
838 "for the lifetime automatically: that is, the lifetime name is guaranteed to "
839 "refer to a distinct lifetime from the lifetimes of all other parameters."
843 #: doc/tutorial-borrowed-ptr.md:518
845 "Named lifetimes that appear in function signatures are conceptually the same "
846 "as the other lifetimes we have seen before, but they are a bit abstract: "
847 "they don’t refer to a specific expression within `get_x()`, but rather to "
848 "some expression within the *caller of `get_x()`*. The lifetime `r` is "
849 "actually a kind of *lifetime parameter*: it is defined by the caller to "
850 "`get_x()`, just as the value for the parameter `p` is defined by that caller."
854 #: doc/tutorial-borrowed-ptr.md:523
856 "In any case, whatever the lifetime of `r` is, the pointer produced by `&p.x` "
857 "always has the same lifetime as `p` itself: a pointer to a field of a struct "
858 "is valid as long as the struct is valid. Therefore, the compiler accepts the "
859 "function `get_x()`."
863 #: doc/tutorial-borrowed-ptr.md:526
865 "To emphasize this point, let’s look at a variation on the example, this time "
866 "one that does not compile:"
870 #: doc/tutorial-borrowed-ptr.md:533
873 "~~~ {.xfail-test}\n"
874 "struct Point {x: float, y: float}\n"
875 "fn get_x_sh(p: @Point) -> &float {\n"
876 " &p.x // Error reported here\n"
882 #: doc/tutorial-borrowed-ptr.md:541
884 "Here, the function `get_x_sh()` takes a managed box as input and returns a "
885 "borrowed pointer. As before, the lifetime of the borrowed pointer that will "
886 "be returned is a parameter (specified by the caller). That means that "
887 "`get_x_sh()` promises to return a borrowed pointer that is valid for as long "
888 "as the caller would like: this is subtly different from the first example, "
889 "which promised to return a pointer that was valid for as long as its pointer "
890 "argument was valid."
894 #: doc/tutorial-borrowed-ptr.md:552
896 "Within `get_x_sh()`, we see the expression `&p.x` which takes the address of "
897 "a field of a managed box. The presence of this expression implies that the "
898 "compiler must guarantee that, so long as the resulting pointer is valid, the "
899 "managed box will not be reclaimed by the garbage collector. But recall that "
900 "`get_x_sh()` also promised to return a pointer that was valid for as long as "
901 "the caller wanted it to be. Clearly, `get_x_sh()` is not in a position to "
902 "make both of these guarantees; in fact, it cannot guarantee that the pointer "
903 "will remain valid at all once it returns, as the parameter `p` may or may "
904 "not be live in the caller. Therefore, the compiler will report an error here."
908 #: doc/tutorial-borrowed-ptr.md:559
910 "In general, if you borrow a managed (or owned) box to create a borrowed "
911 "pointer, the pointer will only be valid within the function and cannot be "
912 "returned. This is why the typical way to return borrowed pointers is to take "
913 "borrowed pointers as input (the only other case in which it can be legal to "
914 "return a borrowed pointer is if the pointer points at a static constant)."
918 #: doc/tutorial-borrowed-ptr.md:561
919 msgid "# Named lifetimes"
923 #: doc/tutorial-borrowed-ptr.md:565
925 "Let's look at named lifetimes in more detail. Named lifetimes allow for "
926 "grouping of parameters by lifetime. For example, consider this function:"
930 #: doc/tutorial-borrowed-ptr.md:579
934 "# struct Point {x: float, y: float}; // as before\n"
935 "# struct Size {w: float, h: float}; // as before\n"
937 "# Circle(Point, float), // origin, radius\n"
938 "# Rectangle(Point, Size) // upper-left, dimensions\n"
940 "# fn compute_area(shape: &Shape) -> float { 0f }\n"
941 "fn select<'r, T>(shape: &'r Shape, threshold: float,\n"
942 " a: &'r T, b: &'r T) -> &'r T {\n"
943 " if compute_area(shape) > threshold {a} else {b}\n"
949 #: doc/tutorial-borrowed-ptr.md:585
951 "This function takes three borrowed pointers and assigns each the same "
952 "lifetime `r`. In practice, this means that, in the caller, the lifetime `r` "
953 "will be the *intersection of the lifetime of the three region parameters*. "
954 "This may be overly conservative, as in this example:"
958 #: doc/tutorial-borrowed-ptr.md:607
962 "# struct Point {x: float, y: float}; // as before\n"
963 "# struct Size {w: float, h: float}; // as before\n"
965 "# Circle(Point, float), // origin, radius\n"
966 "# Rectangle(Point, Size) // upper-left, dimensions\n"
968 "# fn compute_area(shape: &Shape) -> float { 0f }\n"
969 "# fn select<'r, T>(shape: &Shape, threshold: float,\n"
970 "# a: &'r T, b: &'r T) -> &'r T {\n"
971 "# if compute_area(shape) > threshold {a} else {b}\n"
974 "fn select_based_on_unit_circle<'r, T>( // |-+ B\n"
975 " threshold: float, a: &'r T, b: &'r T) -> &'r T { // | |\n"
977 " let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |\n"
978 " select(&shape, threshold, a, b) // | |\n"
985 #: doc/tutorial-borrowed-ptr.md:617
987 "In this call to `select()`, the lifetime of the first parameter shape is B, "
988 "the function body. Both of the second two parameters `a` and `b` share the "
989 "same lifetime, `r`, which is a lifetime parameter of "
990 "`select_based_on_unit_circle()`. The caller will infer the intersection of "
991 "these two lifetimes as the lifetime of the returned value, and hence the "
992 "return value of `select()` will be assigned a lifetime of B. This will in "
993 "turn lead to a compilation error, because `select_based_on_unit_circle()` is "
994 "supposed to return a value with the lifetime `r`."
998 #: doc/tutorial-borrowed-ptr.md:622
1000 "To address this, we can modify the definition of `select()` to distinguish "
1001 "the lifetime of the first parameter from the lifetime of the latter two. "
1002 "After all, the first parameter is not being returned. Here is how the new "
1003 "`select()` might look:"
1007 #: doc/tutorial-borrowed-ptr.md:636
1011 "# struct Point {x: float, y: float}; // as before\n"
1012 "# struct Size {w: float, h: float}; // as before\n"
1014 "# Circle(Point, float), // origin, radius\n"
1015 "# Rectangle(Point, Size) // upper-left, dimensions\n"
1017 "# fn compute_area(shape: &Shape) -> float { 0f }\n"
1018 "fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: float,\n"
1019 " a: &'r T, b: &'r T) -> &'r T {\n"
1020 " if compute_area(shape) > threshold {a} else {b}\n"
1026 #: doc/tutorial-borrowed-ptr.md:641
1028 "Here you can see that `shape`'s lifetime is now named `tmp`. The parameters "
1029 "`a`, `b`, and the return value all have the lifetime `r`. However, since "
1030 "the lifetime `tmp` is not returned, it would be more concise to just omit "
1031 "the named lifetime for `shape` altogether:"
1035 #: doc/tutorial-borrowed-ptr.md:655
1039 "# struct Point {x: float, y: float}; // as before\n"
1040 "# struct Size {w: float, h: float}; // as before\n"
1042 "# Circle(Point, float), // origin, radius\n"
1043 "# Rectangle(Point, Size) // upper-left, dimensions\n"
1045 "# fn compute_area(shape: &Shape) -> float { 0f }\n"
1046 "fn select<'r, T>(shape: &Shape, threshold: float,\n"
1047 " a: &'r T, b: &'r T) -> &'r T {\n"
1048 " if compute_area(shape) > threshold {a} else {b}\n"
1054 #: doc/tutorial-borrowed-ptr.md:657
1055 msgid "This is equivalent to the previous definition."
1059 #: doc/tutorial-borrowed-ptr.md:659
1060 msgid "# Conclusion"
1064 #: doc/tutorial-borrowed-ptr.md:663
1066 "So there you have it: a (relatively) brief tour of the borrowed pointer "
1067 "system. For more details, we refer to the (yet to be written) reference "
1068 "document on borrowed pointers, which will explain the full notation and give "