# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The Rust Project Developers # This file is distributed under the same license as the Rust package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Rust 0.8-pre\n" "POT-Creation-Date: 2013-07-22 23:37+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Plain text #: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4 #: doc/tutorial-borrowed-ptr.md:4 doc/tutorial-ffi.md:4 #: doc/tutorial-macros.md:4 doc/tutorial-tasks.md:4 msgid "# Introduction" msgstr "" #. type: Plain text #: doc/tutorial.md:1108 doc/tutorial-borrowed-ptr.md:72 msgid "Now we can call `compute_distance()` in various ways:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:2 msgid "% Rust Borrowed Pointers Tutorial" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:14 msgid "" "Borrowed pointers are one of the more flexible and powerful tools available " "in Rust. A borrowed pointer can point anywhere: into the managed or exchange " "heap, into the stack, and even into the interior of another data structure. " "A borrowed pointer is as flexible as a C pointer or C++ reference. However, " "unlike C and C++ compilers, the Rust compiler includes special static checks " "that ensure that programs use borrowed pointers safely. Another advantage of " "borrowed pointers is that they are invisible to the garbage collector, so " "working with borrowed pointers helps reduce the overhead of automatic memory " "management." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:18 msgid "" "Despite their complete safety, a borrowed pointer's representation at " "runtime is the same as that of an ordinary pointer in a C program. They " "introduce zero overhead. The compiler does all safety checks at compile time." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:24 msgid "" "Although borrowed pointers have rather elaborate theoretical underpinnings " "(region pointers), the core concepts will be familiar to anyone who has " "worked with C or C++. Therefore, the best way to explain how they are used—" "and their limitations—is probably just to work through several examples." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:26 msgid "# By example" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:31 msgid "" "Borrowed pointers are called *borrowed* because they are only valid for a " "limited duration. Borrowed pointers never claim any kind of ownership over " "the data that they point to: instead, they are used for cases where you " "would like to use data for a short time." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:33 msgid "As an example, consider a simple struct type `Point`:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:37 msgid "~~~ struct Point {x: float, y: float} ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:41 msgid "" "We can use this simple definition to allocate points in many different ways. " "For example, in this code, each of these three local variables contains a " "point, but allocated in a different place:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:48 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}\n" "let on_the_stack : Point = Point {x: 3.0, y: 4.0};\n" "let managed_box : @Point = @Point {x: 5.0, y: 1.0};\n" "let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:60 msgid "" "Suppose we wanted to write a procedure that computed the distance between " "any two points, no matter where they were stored. For example, we might like " "to compute the distance between `on_the_stack` and `managed_box`, or between " "`managed_box` and `owned_box`. One option is to define a function that takes " "two arguments of type `Point`—that is, it takes the points by value. But if " "we define it this way, calling the function will cause the points to be " "copied. For points, this is probably not so bad, but often copies are " "expensive. Worse, if the data type contains mutable fields, copying can " "change the semantics of your program in unexpected ways. So we'd like to " "define a function that takes the points by pointer. We can use borrowed " "pointers to do this:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:70 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}\n" "# fn sqrt(f: float) -> float { 0f }\n" "fn compute_distance(p1: &Point, p2: &Point) -> float {\n" " let x_d = p1.x - p2.x;\n" " let y_d = p1.y - p2.y;\n" " sqrt(x_d * x_d + y_d * y_d)\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:82 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}\n" "# let on_the_stack : Point = Point{x: 3.0, y: 4.0};\n" "# let managed_box : @Point = @Point{x: 5.0, y: 1.0};\n" "# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};\n" "# fn compute_distance(p1: &Point, p2: &Point) -> float { 0f }\n" "compute_distance(&on_the_stack, managed_box);\n" "compute_distance(managed_box, owned_box);\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:89 msgid "" "Here, the `&` operator takes the address of the variable `on_the_stack`; " "this is because `on_the_stack` has the type `Point` (that is, a struct " "value) and we have to take its address to get a value. We also call this " "_borrowing_ the local variable `on_the_stack`, because we have created an " "alias: that is, another name for the same data." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:95 msgid "" "In contrast, we can pass the boxes `managed_box` and `owned_box` to " "`compute_distance` directly. The compiler automatically converts a box like " "`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another " "form of borrowing: in this case, the caller lends the contents of the " "managed or owned box to the callee." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:105 msgid "" "Whenever a caller lends data to a callee, there are some limitations on what " "the caller can do with the original. For example, if the contents of a " "variable have been lent out, you cannot send that variable to another task. " "In addition, the compiler will reject any code that might cause the borrowed " "value to be freed or overwrite its component fields with values of different " "types (I'll get into what kinds of actions those are shortly). This rule " "should make intuitive sense: you must wait for a borrower to return the " "value that you lent it (that is, wait for the borrowed pointer to go out of " "scope) before you can make full use of it again." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:107 msgid "# Other uses for the & operator" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:109 msgid "In the previous example, the value `on_the_stack` was defined like so:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:114 msgid "" "~~~ # struct Point {x: float, y: float} let on_the_stack: Point = Point {x: " "3.0, y: 4.0}; ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:119 msgid "" "This declaration means that code can only pass `Point` by value to other " "functions. As a consequence, we had to explicitly take the address of " "`on_the_stack` to get a borrowed pointer. Sometimes however it is more " "convenient to move the & operator into the definition of `on_the_stack`:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:124 msgid "" "~~~ # struct Point {x: float, y: float} let on_the_stack2: &Point = &Point " "{x: 3.0, y: 4.0}; ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:128 msgid "" "Applying `&` to an rvalue (non-assignable location) is just a convenient " "shorthand for creating a temporary and taking its address. A more verbose " "way to write the same code is:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:134 msgid "" "~~~ # struct Point {x: float, y: float} let tmp = Point {x: 3.0, y: 4.0}; " "let on_the_stack2 : &Point = &tmp; ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:136 msgid "# Taking the address of fields" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:141 msgid "" "As in C, the `&` operator is not limited to taking the address of local " "variables. It can also take the address of fields or individual array " "elements. For example, consider this type definition for `rectangle`:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:147 msgid "" "~~~ struct Point {x: float, y: float} // as before struct Size {w: float, h: " "float} // as before struct Rectangle {origin: Point, size: Size} ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:149 msgid "Now, as before, we can define rectangles in a few different ways:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:161 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}\n" "# struct Size {w: float, h: float} // as before\n" "# struct Rectangle {origin: Point, size: Size}\n" "let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f},\n" " size: Size {w: 3f, h: 4f}};\n" "let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f},\n" " size: Size {w: 3f, h: 4f}};\n" "let rect_owned = ~Rectangle {origin: Point {x: 5f, y: 6f},\n" " size: Size {w: 3f, h: 4f}};\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:164 msgid "" "In each case, we can extract out individual subcomponents with the `&` " "operator. For example, I could write:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:175 msgid "" "~~~ # struct Point {x: float, y: float} // as before # struct Size {w: " "float, h: float} // as before # struct Rectangle {origin: Point, size: Size} " "# let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f}, size: Size {w: " "3f, h: 4f}}; # let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f}, " "size: Size {w: 3f, h: 4f}}; # let rect_owned = ~Rectangle {origin: Point {x: " "5f, y: 6f}, size: Size {w: 3f, h: 4f}}; # fn compute_distance(p1: &Point, " "p2: &Point) -> float { 0f } compute_distance(&rect_stack.origin, " "&rect_managed.origin); ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:178 msgid "" "which would borrow the field `origin` from the rectangle on the stack as " "well as from the managed box, and then compute the distance between them." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:180 msgid "# Borrowing managed boxes and rooting" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:186 msgid "" "We’ve seen a few examples so far of borrowing heap boxes, both managed and " "owned. Up till this point, we’ve glossed over issues of safety. As stated in " "the introduction, at runtime a borrowed pointer is simply a pointer, nothing " "more. Therefore, avoiding C's problems with dangling pointers requires a " "compile-time safety check." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:197 msgid "" "The basis for the check is the notion of _lifetimes_. A lifetime is a static " "approximation of the span of execution during which the pointer is valid: it " "always corresponds to some expression or block within the program. Code " "inside that expression can use the pointer without restrictions. But if the " "pointer escapes from that expression (for example, if the expression " "contains an assignment expression that assigns the pointer to a mutable " "field of a data structure with a broader scope than the pointer itself), the " "compiler reports an error. We'll be discussing lifetimes more in the " "examples to come, and a more thorough introduction is also available." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:202 msgid "" "When the `&` operator creates a borrowed pointer, the compiler must ensure " "that the pointer remains valid for its entire lifetime. Sometimes this is " "relatively easy, such as when taking the address of a local variable or a " "field that is stored on the stack:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:211 #, no-wrap msgid "" "~~~\n" "struct X { f: int }\n" "fn example1() {\n" " let mut x = X { f: 3 };\n" " let y = &mut x.f; // -+ L\n" " ... // |\n" "} // -+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:216 msgid "" "Here, the lifetime of the borrowed pointer `y` is simply L, the remainder of " "the function body. The compiler need not do any other work to prove that " "code will not free `x.f`. This is true even if the code mutates `x`." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:218 msgid "The situation gets more complex when borrowing data inside heap boxes:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:227 #, no-wrap msgid "" "~~~\n" "# struct X { f: int }\n" "fn example2() {\n" " let mut x = @X { f: 3 };\n" " let y = &x.f; // -+ L\n" " ... // |\n" "} // -+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:238 msgid "" "In this example, the value `x` is a heap box, and `y` is therefore a pointer " "into that heap box. Again the lifetime of `y` is L, the remainder of the " "function body. But there is a crucial difference: suppose `x` were to be " "reassigned during the lifetime L? If the compiler isn't careful, the managed " "box could become *unrooted*, and would therefore be subject to garbage " "collection. A heap box that is unrooted is one such that no pointer values " "in the heap point to it. It would violate memory safety for the box that was " "originally assigned to `x` to be garbage-collected, since a non-heap pointer " "*`y`* still points into it." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:241 msgid "" "> ***Note:*** Our current implementation implements the garbage collector > " "using reference counting and cycle detection." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:247 msgid "" "For this reason, whenever an `&` expression borrows the interior of a " "managed box stored in a mutable location, the compiler inserts a temporary " "that ensures that the managed box remains live for the entire lifetime. So, " "the above example would be compiled as if it were written" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:257 #, no-wrap msgid "" "~~~\n" "# struct X { f: int }\n" "fn example2() {\n" " let mut x = @X {f: 3};\n" " let x1 = x;\n" " let y = &x1.f; // -+ L\n" " ... // |\n" "} // -+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:260 msgid "" "Now if `x` is reassigned, the pointer `y` will still remain valid. This " "process is called *rooting*." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:262 msgid "# Borrowing owned boxes" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:268 msgid "" "The previous example demonstrated *rooting*, the process by which the " "compiler ensures that managed boxes remain live for the duration of a " "borrow. Unfortunately, rooting does not work for borrows of owned boxes, " "because it is not possible to have two references to a owned box." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:274 msgid "" "For owned boxes, therefore, the compiler will only allow a borrow *if the " "compiler can guarantee that the owned box will not be reassigned or moved " "for the lifetime of the pointer*. This does not necessarily mean that the " "owned box is stored in immutable memory. For example, the following function " "is legal:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:289 #, no-wrap msgid "" "~~~\n" "# fn some_condition() -> bool { true }\n" "# struct Foo { f: int }\n" "fn example3() -> int {\n" " let mut x = ~Foo {f: 3};\n" " if some_condition() {\n" " let y = &x.f; // -+ L\n" " return *y; // |\n" " } // -+\n" " x = ~Foo {f: 4};\n" " ...\n" "# return 0;\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:295 msgid "" "Here, as before, the interior of the variable `x` is being borrowed and `x` " "is declared as mutable. However, the compiler can prove that `x` is not " "assigned anywhere in the lifetime L of the variable `y`. Therefore, it " "accepts the function, even though `x` is mutable and in fact is mutated " "later in the function." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:301 msgid "" "It may not be clear why we are so concerned about mutating a borrowed " "variable. The reason is that the runtime system frees any owned box _as soon " "as its owning reference changes or goes out of scope_. Therefore, a program " "like this is illegal (and would be rejected by the compiler):" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:310 #, no-wrap msgid "" "~~~ {.xfail-test}\n" "fn example3() -> int {\n" " let mut x = ~X {f: 3};\n" " let y = &x.f;\n" " x = ~X {f: 4}; // Error reported here.\n" " *y\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:313 msgid "" "To make this clearer, consider this diagram showing the state of memory " "immediately before the re-assignment of `x`:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:316 doc/tutorial-borrowed-ptr.md:330 #, no-wrap msgid "" "~~~ {.notrust}\n" " Stack Exchange Heap\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:325 #, no-wrap msgid "" " x +----------+\n" " | ~{f:int} | ----+\n" " y +----------+ |\n" " | &int | ----+\n" " +----------+ | +---------+\n" " +--> | f: 3 |\n" " +---------+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:327 msgid "Once the reassignment occurs, the memory will look like this:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:339 #, no-wrap msgid "" " x +----------+ +---------+\n" " | ~{f:int} | -------> | f: 4 |\n" " y +----------+ +---------+\n" " | &int | ----+\n" " +----------+ | +---------+\n" " +--> | (freed) |\n" " +---------+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:342 msgid "" "Here you can see that the variable `y` still points at the old box, which " "has been freed." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:348 msgid "" "In fact, the compiler can apply the same kind of reasoning to any memory " "that is _(uniquely) owned by the stack frame_. So we could modify the " "previous example to introduce additional owned pointers and structs, and the " "compiler will still be able to detect possible mutations:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:353 #, no-wrap msgid "" "~~~ {.xfail-test}\n" "fn example3() -> int {\n" " struct R { g: int }\n" " struct S { f: ~R }\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:361 #, no-wrap msgid "" " let mut x = ~S {f: ~R {g: 3}};\n" " let y = &x.f.g;\n" " x = ~S {f: ~R {g: 4}}; // Error reported here.\n" " x.f = ~R {g: 5}; // Error reported here.\n" " *y\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:365 msgid "" "In this case, two errors are reported, one when the variable `x` is modified " "and another when `x.f` is modified. Either modification would invalidate the " "pointer `y`." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:367 msgid "# Borrowing and enums" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:373 msgid "" "The previous example showed that the type system forbids any borrowing of " "owned boxes found in aliasable, mutable memory. This restriction prevents " "pointers from pointing into freed memory. There is one other case where the " "compiler must be very careful to ensure that pointers remain valid: pointers " "into the interior of an `enum`." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:376 msgid "" "As an example, let’s look at the following `shape` type that can represent " "both rectangles and circles:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:385 #, no-wrap msgid "" "~~~\n" "struct Point {x: float, y: float}; // as before\n" "struct Size {w: float, h: float}; // as before\n" "enum Shape {\n" " Circle(Point, float), // origin, radius\n" " Rectangle(Point, Size) // upper-left, dimensions\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:389 msgid "" "Now we might write a function to compute the area of a shape. This function " "takes a borrowed pointer to a shape, to avoid the need for copying." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:405 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}; // as before\n" "# struct Size {w: float, h: float}; // as before\n" "# enum Shape {\n" "# Circle(Point, float), // origin, radius\n" "# Rectangle(Point, Size) // upper-left, dimensions\n" "# }\n" "# static tau: float = 6.28f;\n" "fn compute_area(shape: &Shape) -> float {\n" " match *shape {\n" " Circle(_, radius) => 0.5 * tau * radius * radius,\n" " Rectangle(_, ref size) => size.w * size.h\n" " }\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:410 msgid "" "The first case matches against circles. Here, the pattern extracts the " "radius from the shape variant and the action uses it to compute the area of " "the circle. (Like any up-to-date engineer, we use the [tau circle constant]" "[tau] and not that dreadfully outdated notion of pi)." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:412 msgid "[tau]: http://www.math.utah.edu/~palais/pi.html" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:418 msgid "" "The second match is more interesting. Here we match against a rectangle and " "extract its size: but rather than copy the `size` struct, we use a by-" "reference binding to create a pointer to it. In other words, a pattern " "binding like `ref size` binds the name `size` to a pointer of type `&size` " "into the _interior of the enum_." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:421 msgid "" "To make this more clear, let's look at a diagram of memory layout in the " "case where `shape` points at a rectangle:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:424 doc/tutorial-borrowed-ptr.md:449 #, no-wrap msgid "" "~~~ {.notrust}\n" "Stack Memory\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:433 #, no-wrap msgid "" "+-------+ +---------------+\n" "| shape | ------> | rectangle( |\n" "+-------+ | {x: float, |\n" "| size | -+ | y: float}, |\n" "+-------+ +----> | {w: float, |\n" " | h: float}) |\n" " +---------------+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:440 msgid "" "Here you can see that rectangular shapes are composed of five words of " "memory. The first is a tag indicating which variant this enum is " "(`rectangle`, in this case). The next two words are the `x` and `y` fields " "for the point and the remaining two are the `w` and `h` fields for the size. " "The binding `size` is then a pointer into the inside of the shape." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:446 msgid "" "Perhaps you can see where the danger lies: if the shape were somehow to be " "reassigned, perhaps to a circle, then although the memory used to store that " "shape value would still be valid, _it would have a different type_! The " "following diagram shows what memory would look like if code overwrote " "`shape` with a circle:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:458 #, no-wrap msgid "" "+-------+ +---------------+\n" "| shape | ------> | circle( |\n" "+-------+ | {x: float, |\n" "| size | -+ | y: float}, |\n" "+-------+ +----> | float) |\n" " | |\n" " +---------------+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:463 msgid "" "As you can see, the `size` pointer would be pointing at a `float` instead of " "a struct. This is not good: dereferencing the second field of a `float` as " "if it were a struct with two fields would be a memory safety violation." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:475 msgid "" "So, in fact, for every `ref` binding, the compiler will impose the same " "rules as the ones we saw for borrowing the interior of a owned box: it must " "be able to guarantee that the `enum` will not be overwritten for the " "duration of the borrow. In fact, the compiler would accept the example we " "gave earlier. The example is safe because the shape pointer has type " "`&Shape`, which means \"borrowed pointer to immutable memory containing a " "`shape`\". If, however, the type of that pointer were `&mut Shape`, then the " "ref binding would be ill-typed. Just as with owned boxes, the compiler will " "permit `ref` bindings into data owned by the stack frame even if the data " "are mutable, but otherwise it requires that the data reside in immutable " "memory." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:477 msgid "# Returning borrowed pointers" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:483 msgid "" "So far, all of the examples we have looked at, use borrowed pointers in a " "“downward” direction. That is, a method or code block creates a borrowed " "pointer, then uses it within the same scope. It is also possible to return " "borrowed pointers as the result of a function, but as we'll see, doing so " "requires some explicit annotation." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:485 msgid "For example, we could write a subroutine like this:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:490 msgid "" "~~~ struct Point {x: float, y: float} fn get_x<'r>(p: &'r Point) -> &'r " "float { &p.x } ~~~" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:498 msgid "" "Here, the function `get_x()` returns a pointer into the structure it was " "given. The type of the parameter (`&'r Point`) and return type (`&'r float`) " "both use a new syntactic form that we have not seen so far. Here the " "identifier `r` names the lifetime of the pointer explicitly. So in effect, " "this function declares that it takes a pointer with lifetime `r` and returns " "a pointer with that same lifetime." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:504 msgid "" "In general, it is only possible to return borrowed pointers if they are " "derived from a parameter to the procedure. In that case, the pointer result " "will always have the same lifetime as one of the parameters; named lifetimes " "indicate which parameter that is." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:510 msgid "" "In the previous examples, function parameter types did not include a " "lifetime name. In those examples, the compiler simply creates a fresh name " "for the lifetime automatically: that is, the lifetime name is guaranteed to " "refer to a distinct lifetime from the lifetimes of all other parameters." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:518 msgid "" "Named lifetimes that appear in function signatures are conceptually the same " "as the other lifetimes we have seen before, but they are a bit abstract: " "they don’t refer to a specific expression within `get_x()`, but rather to " "some expression within the *caller of `get_x()`*. The lifetime `r` is " "actually a kind of *lifetime parameter*: it is defined by the caller to " "`get_x()`, just as the value for the parameter `p` is defined by that caller." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:523 msgid "" "In any case, whatever the lifetime of `r` is, the pointer produced by `&p.x` " "always has the same lifetime as `p` itself: a pointer to a field of a struct " "is valid as long as the struct is valid. Therefore, the compiler accepts the " "function `get_x()`." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:526 msgid "" "To emphasize this point, let’s look at a variation on the example, this time " "one that does not compile:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:533 #, no-wrap msgid "" "~~~ {.xfail-test}\n" "struct Point {x: float, y: float}\n" "fn get_x_sh(p: @Point) -> &float {\n" " &p.x // Error reported here\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:541 msgid "" "Here, the function `get_x_sh()` takes a managed box as input and returns a " "borrowed pointer. As before, the lifetime of the borrowed pointer that will " "be returned is a parameter (specified by the caller). That means that " "`get_x_sh()` promises to return a borrowed pointer that is valid for as long " "as the caller would like: this is subtly different from the first example, " "which promised to return a pointer that was valid for as long as its pointer " "argument was valid." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:552 msgid "" "Within `get_x_sh()`, we see the expression `&p.x` which takes the address of " "a field of a managed box. The presence of this expression implies that the " "compiler must guarantee that, so long as the resulting pointer is valid, the " "managed box will not be reclaimed by the garbage collector. But recall that " "`get_x_sh()` also promised to return a pointer that was valid for as long as " "the caller wanted it to be. Clearly, `get_x_sh()` is not in a position to " "make both of these guarantees; in fact, it cannot guarantee that the pointer " "will remain valid at all once it returns, as the parameter `p` may or may " "not be live in the caller. Therefore, the compiler will report an error here." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:559 msgid "" "In general, if you borrow a managed (or owned) box to create a borrowed " "pointer, the pointer will only be valid within the function and cannot be " "returned. This is why the typical way to return borrowed pointers is to take " "borrowed pointers as input (the only other case in which it can be legal to " "return a borrowed pointer is if the pointer points at a static constant)." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:561 msgid "# Named lifetimes" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:565 msgid "" "Let's look at named lifetimes in more detail. Named lifetimes allow for " "grouping of parameters by lifetime. For example, consider this function:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:579 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}; // as before\n" "# struct Size {w: float, h: float}; // as before\n" "# enum Shape {\n" "# Circle(Point, float), // origin, radius\n" "# Rectangle(Point, Size) // upper-left, dimensions\n" "# }\n" "# fn compute_area(shape: &Shape) -> float { 0f }\n" "fn select<'r, T>(shape: &'r Shape, threshold: float,\n" " a: &'r T, b: &'r T) -> &'r T {\n" " if compute_area(shape) > threshold {a} else {b}\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:585 msgid "" "This function takes three borrowed pointers and assigns each the same " "lifetime `r`. In practice, this means that, in the caller, the lifetime `r` " "will be the *intersection of the lifetime of the three region parameters*. " "This may be overly conservative, as in this example:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:607 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}; // as before\n" "# struct Size {w: float, h: float}; // as before\n" "# enum Shape {\n" "# Circle(Point, float), // origin, radius\n" "# Rectangle(Point, Size) // upper-left, dimensions\n" "# }\n" "# fn compute_area(shape: &Shape) -> float { 0f }\n" "# fn select<'r, T>(shape: &Shape, threshold: float,\n" "# a: &'r T, b: &'r T) -> &'r T {\n" "# if compute_area(shape) > threshold {a} else {b}\n" "# }\n" " // -+ r\n" "fn select_based_on_unit_circle<'r, T>( // |-+ B\n" " threshold: float, a: &'r T, b: &'r T) -> &'r T { // | |\n" " // | |\n" " let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |\n" " select(&shape, threshold, a, b) // | |\n" "} // |-+\n" " // -+\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:617 msgid "" "In this call to `select()`, the lifetime of the first parameter shape is B, " "the function body. Both of the second two parameters `a` and `b` share the " "same lifetime, `r`, which is a lifetime parameter of " "`select_based_on_unit_circle()`. The caller will infer the intersection of " "these two lifetimes as the lifetime of the returned value, and hence the " "return value of `select()` will be assigned a lifetime of B. This will in " "turn lead to a compilation error, because `select_based_on_unit_circle()` is " "supposed to return a value with the lifetime `r`." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:622 msgid "" "To address this, we can modify the definition of `select()` to distinguish " "the lifetime of the first parameter from the lifetime of the latter two. " "After all, the first parameter is not being returned. Here is how the new " "`select()` might look:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:636 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}; // as before\n" "# struct Size {w: float, h: float}; // as before\n" "# enum Shape {\n" "# Circle(Point, float), // origin, radius\n" "# Rectangle(Point, Size) // upper-left, dimensions\n" "# }\n" "# fn compute_area(shape: &Shape) -> float { 0f }\n" "fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: float,\n" " a: &'r T, b: &'r T) -> &'r T {\n" " if compute_area(shape) > threshold {a} else {b}\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:641 msgid "" "Here you can see that `shape`'s lifetime is now named `tmp`. The parameters " "`a`, `b`, and the return value all have the lifetime `r`. However, since " "the lifetime `tmp` is not returned, it would be more concise to just omit " "the named lifetime for `shape` altogether:" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:655 #, no-wrap msgid "" "~~~\n" "# struct Point {x: float, y: float}; // as before\n" "# struct Size {w: float, h: float}; // as before\n" "# enum Shape {\n" "# Circle(Point, float), // origin, radius\n" "# Rectangle(Point, Size) // upper-left, dimensions\n" "# }\n" "# fn compute_area(shape: &Shape) -> float { 0f }\n" "fn select<'r, T>(shape: &Shape, threshold: float,\n" " a: &'r T, b: &'r T) -> &'r T {\n" " if compute_area(shape) > threshold {a} else {b}\n" "}\n" "~~~\n" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:657 msgid "This is equivalent to the previous definition." msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:659 msgid "# Conclusion" msgstr "" #. type: Plain text #: doc/tutorial-borrowed-ptr.md:663 msgid "" "So there you have it: a (relatively) brief tour of the borrowed pointer " "system. For more details, we refer to the (yet to be written) reference " "document on borrowed pointers, which will explain the full notation and give " "more examples." msgstr ""