@@ -447,11 +447,11 @@ the block restricts the scope of `y`, making the move legal.
447
447
448
448
# Borrowing and enums
449
449
450
- The previous example showed that borrowing unique boxes found in
451
- aliasable, mutable memory is not permitted, so as to prevent pointers
452
- into freed memory. There is one other case where the compiler must be
453
- very careful to ensure that pointers remain valid: pointers into the
454
- interior of an enum.
450
+ The previous example showed that the type system forbids any borrowing
451
+ of unique boxes found in aliasable, mutable memory. This restriction
452
+ prevents pointers from pointing into freed memory. There is one other
453
+ case where the compiler must be very careful to ensure that pointers
454
+ remain valid: pointers into the interior of an ` enum ` .
455
455
456
456
As an example, let’s look at the following ` shape ` type that can
457
457
represent both rectangles and circles:
@@ -465,9 +465,9 @@ enum Shape {
465
465
}
466
466
~~~
467
467
468
- Now I might write a function to compute the area of a shape. This
469
- function takes a borrowed pointer to a shape to avoid the need of
470
- copying them .
468
+ Now we might write a function to compute the area of a shape. This
469
+ function takes a borrowed pointer to a shape, to avoid the need for
470
+ copying.
471
471
472
472
~~~
473
473
# struct Point {x: float, y: float}; // as before
@@ -485,21 +485,21 @@ fn compute_area(shape: &Shape) -> float {
485
485
}
486
486
~~~
487
487
488
- The first case matches against circles. Here the radius is extracted
489
- from the shape variant and used to compute the area of the circle
490
- (Like any up-to-date engineer, we use the [ tau circle constant ] [ tau ]
491
- and not that dreadfully outdated notion of pi).
488
+ The first case matches against circles. Here, the pattern extracts the
489
+ radius from the shape variant and the action uses it to compute the
490
+ area of the circle. (Like any up-to-date engineer, we use the [ tau
491
+ circle constant ] [ tau ] and not that dreadfully outdated notion of pi).
492
492
493
493
[ tau ] : http://www.math.utah.edu/~palais/pi.html
494
494
495
495
The second match is more interesting. Here we match against a
496
- rectangle and extract its size: but rather than copy the ` size ` struct,
497
- we use a by-reference binding to create a pointer to it. In other
498
- words, a pattern binding like ` ref size ` in fact creates a pointer of
499
- type ` &size ` into the _ interior of the enum_ .
496
+ rectangle and extract its size: but rather than copy the ` size `
497
+ struct, we use a by-reference binding to create a pointer to it. In
498
+ other words, a pattern binding like ` ref size ` binds the name ` size `
499
+ to a pointer of type ` &size ` into the _ interior of the enum_ .
500
500
501
- To make this more clear, let’ s look at a diagram of how things are
502
- laid out in memory in the case where ` shape ` points at a rectangle:
501
+ To make this more clear, let' s look at a diagram of memory layout in
502
+ the case where ` shape ` points at a rectangle:
503
503
504
504
~~~ {.notrust}
505
505
Stack Memory
@@ -523,8 +523,8 @@ the shape.
523
523
Perhaps you can see where the danger lies: if the shape were somehow
524
524
to be reassigned, perhaps to a circle, then although the memory used
525
525
to store that shape value would still be valid, _ it would have a
526
- different type_ ! This is shown in the following diagram, depicting what
527
- the state of memory would be if shape were overwritten with a circle:
526
+ different type_ ! The following diagram shows what memory would look
527
+ like if code overwrote ` shape ` with a circle:
528
528
529
529
~~~ {.notrust}
530
530
Stack Memory
@@ -538,20 +538,23 @@ Stack Memory
538
538
+---------------+
539
539
~~~
540
540
541
- As you can see, the ` size ` pointer would not be pointing at a ` float ` and
542
- not a struct. This is not good.
541
+ As you can see, the ` size ` pointer would be pointing at a ` float `
542
+ instead of a struct. This is not good: dereferencing the second field
543
+ of a ` float ` as if it were a struct with two fields would be a memory
544
+ safety violation.
543
545
544
546
So, in fact, for every ` ref ` binding, the compiler will impose the
545
547
same rules as the ones we saw for borrowing the interior of a unique
546
- box: it must be able to guarantee that the enum will not be
547
- overwritten for the duration of the borrow. In fact, the example I
548
- gave earlier would be considered safe. This is because the shape
549
- pointer has type ` &Shape ` , which means “borrowed pointer to immutable
550
- memory containing a shape”. If however the type of that pointer were
551
- ` &const Shape ` or ` &mut Shape ` , then the ref binding would not be
552
- permitted. Just as with unique boxes, the compiler will permit ref
553
- bindings into data owned by the stack frame even if it is mutable, but
554
- otherwise it requires that the data reside in immutable memory.
548
+ box: it must be able to guarantee that the ` enum ` will not be
549
+ overwritten for the duration of the borrow. In fact, the compiler
550
+ would accept the example we gave earlier. The example is safe because
551
+ the shape pointer has type ` &Shape ` , which means "borrowed pointer to
552
+ immutable memory containing a ` shape ` ". If, however, the type of that
553
+ pointer were ` &const Shape ` or ` &mut Shape ` , then the ref binding
554
+ would be ill-typed. Just as with unique boxes, the compiler will
555
+ permit ` ref ` bindings into data owned by the stack frame even if the
556
+ data are mutable, but otherwise it requires that the data reside in
557
+ immutable memory.
555
558
556
559
> *** Note:*** Right now, pattern bindings not explicitly annotated
557
560
> with ` ref ` or ` copy ` use a special mode of "implicit by reference".
@@ -560,11 +563,11 @@ otherwise it requires that the data reside in immutable memory.
560
563
561
564
# Returning borrowed pointers
562
565
563
- So far, all of the examples we’ ve looked at use borrowed pointers in a
564
- “downward” direction. That is, the borrowed pointer is created and
565
- then used during the method or code block which created it . It is also
566
- possible to return borrowed pointers to the caller, but as we'll see
567
- this requires some explicit annotation.
566
+ So far, all of the examples we' ve looked at use borrowed pointers in a
567
+ “downward” direction. That is, a method or code block creates a
568
+ borrowed pointer, then uses it within the same scope . It is also
569
+ possible to return borrowed pointers as the result of a function, but
570
+ as we'll see, doing so requires some explicit annotation.
568
571
569
572
For example, we could write a subroutine like this:
570
573
@@ -573,23 +576,25 @@ struct Point {x: float, y: float}
573
576
fn get_x(p: &r/Point) -> &r/float { &p.x }
574
577
~~~
575
578
576
- Here, the function ` get_x() ` returns a pointer into the structure it was
577
- given. The type of the parameter (` &r/Point ` ) and return type (` &r/float ` ) both
578
- make use of a new syntactic form that we have not seen so far. Here the identifier ` r `
579
- serves as an explicit name for the lifetime of the pointer. So in effect
580
- this function is declaring that it takes in a pointer with lifetime ` r ` and returns
581
- a pointer with that same lifetime.
579
+ Here, the function ` get_x() ` returns a pointer into the structure it
580
+ was given. The type of the parameter (` &r/Point ` ) and return type
581
+ (` &r/float ` ) both use a new syntactic form that we have not seen so
582
+ far. Here the identifier ` r ` names the lifetime of the pointer
583
+ explicitly. So in effect, this function declares that it takes a
584
+ pointer with lifetime ` r ` and returns a pointer with that same
585
+ lifetime.
582
586
583
587
In general, it is only possible to return borrowed pointers if they
584
- are derived from a borrowed pointer which was given as input to the
585
- procedure. In that case, they will always have the same lifetime as
586
- one of the parameters; named lifetimes are used to indicate which
587
- parameter that is.
588
+ are derived from a parameter to the procedure. In that case, the
589
+ pointer result will always have the same lifetime as one of the
590
+ parameters; named lifetimes indicate which parameter that
591
+ is.
588
592
589
- In the examples before, function parameter types did not include a
590
- lifetime name. In this case, the compiler simply creates a new,
591
- anonymous name, meaning that the parameter is assumed to have a
592
- distinct lifetime from all other parameters.
593
+ In the previous examples, function parameter types did not include a
594
+ lifetime name. In those examples, the compiler simply creates a fresh
595
+ name for the lifetime automatically: that is, the lifetime name is
596
+ guaranteed to refer to a distinct lifetime from the lifetimes of all
597
+ other parameters.
593
598
594
599
Named lifetimes that appear in function signatures are conceptually
595
600
the same as the other lifetimes we've seen before, but they are a bit
@@ -599,13 +604,13 @@ lifetime `r` is actually a kind of *lifetime parameter*: it is defined
599
604
by the caller to ` get_x() ` , just as the value for the parameter ` p ` is
600
605
defined by that caller.
601
606
602
- In any case, whatever the lifetime ` r ` is, the pointer produced by
603
- ` &p.x ` always has the same lifetime as ` p ` itself, as a pointer to a
607
+ In any case, whatever the lifetime of ` r ` is, the pointer produced by
608
+ ` &p.x ` always has the same lifetime as ` p ` itself: a pointer to a
604
609
field of a struct is valid as long as the struct is valid. Therefore,
605
- the compiler is satisfied with the function ` get_x() ` .
610
+ the compiler accepts the function ` get_x() ` .
606
611
607
- To drill in this point, let’s look at a variation on the example, this
608
- time one which does not compile:
612
+ To emphasize this point, let’s look at a variation on the example, this
613
+ time one that does not compile:
609
614
610
615
~~~ {.xfail-test}
611
616
struct Point {x: float, y: float}
@@ -617,22 +622,21 @@ fn get_x_sh(p: @Point) -> &float {
617
622
Here, the function ` get_x_sh() ` takes a managed box as input and
618
623
returns a borrowed pointer. As before, the lifetime of the borrowed
619
624
pointer that will be returned is a parameter (specified by the
620
- caller). That means that effectively ` get_x_sh() ` is promising to
621
- return a borrowed pointer that is valid for as long as the caller
622
- would like: this is subtly different from the first example, which
623
- promised to return a pointer that was valid for as long as the pointer
624
- it was given.
625
+ caller). That means that ` get_x_sh() ` promises to return a borrowed
626
+ pointer that is valid for as long as the caller would like: this is
627
+ subtly different from the first example, which promised to return a
628
+ pointer that was valid for as long as its pointer argument was valid.
625
629
626
630
Within ` get_x_sh() ` , we see the expression ` &p.x ` which takes the
627
- address of a field of a managed box. This implies that the compiler
628
- must guarantee that, so long as the resulting pointer is valid, the
629
- managed box will not be reclaimed by the garbage collector. But recall
630
- that ` get_x_sh() ` also promised to return a pointer that was valid for
631
- as long as the caller wanted it to be. Clearly, ` get_x_sh() ` is not in
632
- a position to make both of these guarantees; in fact, it cannot
633
- guarantee that the pointer will remain valid at all once it returns,
634
- as the parameter ` p ` may or may not be live in the caller. Therefore,
635
- the compiler will report an error here.
631
+ address of a field of a managed box. The presence of this expression
632
+ implies that the compiler must guarantee that, so long as the
633
+ resulting pointer is valid, the managed box will not be reclaimed by
634
+ the garbage collector. But recall that ` get_x_sh() ` also promised to
635
+ return a pointer that was valid for as long as the caller wanted it to
636
+ be. Clearly, ` get_x_sh() ` is not in a position to make both of these
637
+ guarantees; in fact, it cannot guarantee that the pointer will remain
638
+ valid at all once it returns, as the parameter ` p ` may or may not be
639
+ live in the caller. Therefore, the compiler will report an error here.
636
640
637
641
In general, if you borrow a managed (or unique) box to create a
638
642
borrowed pointer, the pointer will only be valid within the function
0 commit comments