@@ -40,6 +40,7 @@ example, in this code, each of these three local variables contains a
40
40
point, but allocated in a different place:
41
41
42
42
~~~
43
+ # type point = {x: float, y: float};
43
44
let on_the_stack : point = {x: 3.0, y: 4.0};
44
45
let shared_box : @point = @{x: 5.0, y: 1.0};
45
46
let unique_box : ~point = ~{x: 7.0, y: 9.0};
@@ -58,6 +59,8 @@ define a function that takes the points by pointer. We can use
58
59
borrowed pointers to do this:
59
60
60
61
~~~
62
+ # type point = {x: float, y: float};
63
+ # fn sqrt(f: float) -> float { 0f }
61
64
fn compute_distance(p1: &point, p2: &point) -> float {
62
65
let x_d = p1.x - p2.x;
63
66
let y_d = p1.y - p2.y;
@@ -67,7 +70,12 @@ fn compute_distance(p1: &point, p2: &point) -> float {
67
70
68
71
Now we can call ` compute_distance() ` in various ways:
69
72
70
- ~~~
73
+ ~~~ {.xfail-test}
74
+ # type point = {x: float, y: float};
75
+ # let on_the_stack : point = {x: 3.0, y: 4.0};
76
+ # let shared_box : @point = @{x: 5.0, y: 1.0};
77
+ # let unique_box : ~point = ~{x: 7.0, y: 9.0};
78
+ # fn compute_distance(p1: &point, p2: &point) -> float { 0f }
71
79
compute_distance(&on_the_stack, shared_box)
72
80
compute_distance(shared_box, unique_box)
73
81
~~~
@@ -100,6 +108,7 @@ it again.
100
108
In the previous example, the value ` on_the_stack ` was defined like so:
101
109
102
110
~~~
111
+ # type point = {x: float, y: float};
103
112
let on_the_stack : point = {x: 3.0, y: 4.0};
104
113
~~~
105
114
@@ -109,13 +118,15 @@ pointer. Sometimes however it is more convenient to move the &
109
118
operator into the definition of ` on_the_stack ` :
110
119
111
120
~~~
121
+ # type point = {x: float, y: float};
112
122
let on_the_stack2 : &point = &{x: 3.0, y: 4.0};
113
123
~~~
114
124
115
125
Applying ` & ` to an rvalue (non-assignable location) is just a convenient
116
126
shorthand for creating a temporary and taking its address:
117
127
118
128
~~~
129
+ # type point = {x: float, y: float};
119
130
let tmp = {x: 3.0, y: 4.0};
120
131
let on_the_stack2 : &point = &tmp;
121
132
~~~
@@ -144,7 +155,14 @@ let rect_unique = ~{origin: {x: 5, y: 6}, size: {w: 3, h: 4}};
144
155
In each case I can use the ` & ` operator to extact out individual
145
156
subcomponents. For example, I could write:
146
157
147
- ~~~
158
+ ~~~ {.xfail-test}
159
+ # type point = {x: float, y: float};
160
+ # type size = {w: float, h: float}; // as before
161
+ # type rectangle = {origin: point, size: size};
162
+ # let rect_stack = &{origin: {x: 1, y: 2}, size: {w: 3, h: 4}};
163
+ # let rect_shared = @{origin: {x: 3, y: 4}, size: {w: 3, h: 4}};
164
+ # let rect_unique = ~{origin: {x: 5, y: 6}, size: {w: 3, h: 4}};
165
+ # fn compute_distance(p1: &point, p2: &point) -> float { 0f }
148
166
compute_distance(&rect_stack.origin, &rect_shared.origin);
149
167
~~~
150
168
@@ -238,14 +256,16 @@ mean that the unique box is stored in immutable memory. For example,
238
256
the following function is legal:
239
257
240
258
~~~
259
+ # fn some_condition() -> bool { true }
241
260
fn example3() -> int {
242
261
let mut x = ~{f: 3};
243
- if some_condition {
262
+ if some_condition() {
244
263
let y = &x.f; // -+ L
245
- ret *y; // |
264
+ return *y; // |
246
265
} // -+
247
266
x = ~{f: 4};
248
267
...
268
+ # return 0;
249
269
}
250
270
~~~
251
271
@@ -261,7 +281,7 @@ _as soon as their owning reference is changed or goes out of
261
281
scope_ . Therefore, a program like this is illegal (and would be
262
282
rejected by the compiler):
263
283
264
- ~~~
284
+ ~~~ {.xfail-test}
265
285
fn example3() -> int {
266
286
let mut x = ~{f: 3};
267
287
let y = &x.f;
@@ -308,7 +328,7 @@ frame_. So we could modify the previous example to introduce
308
328
additional unique pointers and records, and the compiler will still be
309
329
able to detect possible mutations:
310
330
311
- ~~~
331
+ ~~~ {.xfail-test}
312
332
fn example3() -> int {
313
333
let mut x = ~{mut f: ~{g: 3}};
314
334
let y = &x.f.g;
@@ -326,8 +346,8 @@ Things get tricker when the unique box is not uniquely owned by the
326
346
stack frame (or when the compiler doesn’t know who the owner
327
347
is). Consider a program like this:
328
348
329
- ~~~
330
- fn example5a(x: @{mut f: ~{g: int}}, ...) -> int {
349
+ ~~~ {.xfail-test}
350
+ fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
331
351
let y = &x.f.g; // Error reported here.
332
352
...
333
353
}
@@ -359,9 +379,10 @@ unique found in aliasable memory is to ensure that it is stored within
359
379
unique fields, as in the following example:
360
380
361
381
~~~
362
- fn example5b(x: @{f: ~{g: int}}, ... ) -> int {
382
+ fn example5b(x: @{f: ~{g: int}}) -> int {
363
383
let y = &x.f.g;
364
384
...
385
+ # return 0;
365
386
}
366
387
~~~
367
388
@@ -373,13 +394,15 @@ If you do have a unique box in a mutable field, and you wish to borrow
373
394
it, one option is to use the swap operator to bring that unique box
374
395
onto your stack:
375
396
376
- ~~~
377
- fn example5c(x: @{mut f: ~int}, ... ) -> int {
397
+ ~~~ {.xfail-test}
398
+ fn example5c(x: @{mut f: ~int}) -> int {
378
399
let mut v = ~0;
379
400
v <-> x.f; // Swap v and x.f
380
401
let y = &v;
381
402
...
382
403
x.f <- v; // Replace x.f
404
+ ...
405
+ # return 0;
383
406
}
384
407
~~~
385
408
@@ -412,8 +435,15 @@ function takes a borrowed pointer to a shape to avoid the need of
412
435
copying them.
413
436
414
437
~~~
438
+ # type point = {x: float, y: float}; // as before
439
+ # type size = {w: float, h: float}; // as before
440
+ # enum shape {
441
+ # circle(point, float), // origin, radius
442
+ # rectangle(point, size) // upper-left, dimensions
443
+ # }
444
+ # const tau: float = 6.28f;
415
445
fn compute_area(shape: &shape) -> float {
416
- alt *shape {
446
+ match *shape {
417
447
circle(_, radius) => 0.5 * tau * radius * radius,
418
448
rectangle(_, ref size) => size.w * size.h
419
449
}
@@ -502,7 +532,7 @@ but as we’ll see this is more limited.
502
532
503
533
For example, we could write a subroutine like this:
504
534
505
- ~~~
535
+ ~~~ {.xfail-test}
506
536
type point = {x: float, y: float};
507
537
fn get_x(p: &point) -> &float { &p.x }
508
538
~~~
@@ -535,7 +565,7 @@ the compiler is satisfied with the function `get_x()`.
535
565
To drill in this point, let’s look at a variation on the example, this
536
566
time one which does not compile:
537
567
538
- ~~~
568
+ ~~~ {.xfail-test}
539
569
type point = {x: float, y: float};
540
570
fn get_x_sh(p: @point) -> &float {
541
571
&p.x // Error reported here
@@ -574,7 +604,14 @@ pointer. However, sometimes if a function takes many parameters, it is
574
604
useful to be able to group those parameters by lifetime. For example,
575
605
consider this function:
576
606
577
- ~~~
607
+ ~~~ {.xfail-test}
608
+ # type point = {x: float, y: float}; // as before
609
+ # type size = {w: float, h: float}; // as before
610
+ # enum shape {
611
+ # circle(point, float), // origin, radius
612
+ # rectangle(point, size) // upper-left, dimensions
613
+ # }
614
+ # fn compute_area(shape: &shape) -> float { 0f }
578
615
fn select<T>(shape: &shape, threshold: float,
579
616
a: &T, b: &T) -> &T {
580
617
if compute_area(shape) > threshold {a} else {b}
@@ -588,7 +625,19 @@ lifetime of the returned value will be the intersection of the
588
625
lifetime of the three region parameters. This may be overloy
589
626
conservative, as in this example:
590
627
591
- ~~~
628
+ ~~~ {.xfail-test}
629
+ # type point = {x: float, y: float}; // as before
630
+ # type size = {w: float, h: float}; // as before
631
+ # enum shape {
632
+ # circle(point, float), // origin, radius
633
+ # rectangle(point, size) // upper-left, dimensions
634
+ # }
635
+ # fn compute_area(shape: &shape) -> float { 0f }
636
+ # fn select<T>(shape: &shape, threshold: float,
637
+ # a: &T, b: &T) -> &T {
638
+ # if compute_area(shape) > threshold {a} else {b}
639
+ # }
640
+
592
641
// -+ L
593
642
fn select_based_on_unit_circle<T>( // |-+ B
594
643
threshold: float, a: &T, b: &T) -> &T { // | |
@@ -618,7 +667,14 @@ second lifetime parameter for the function; named lifetime parameters
618
667
do not need to be declared, you just use them. Here is how the new
619
668
` select() ` might look:
620
669
621
- ~~~
670
+ ~~~ {.xfail-test}
671
+ # type point = {x: float, y: float}; // as before
672
+ # type size = {w: float, h: float}; // as before
673
+ # enum shape {
674
+ # circle(point, float), // origin, radius
675
+ # rectangle(point, size) // upper-left, dimensions
676
+ # }
677
+ # fn compute_area(shape: &shape) -> float { 0f }
622
678
fn select<T>(shape: &tmp/shape, threshold: float,
623
679
a: &T, b: &T) -> &T {
624
680
if compute_area(shape) > threshold {a} else {b}
@@ -632,7 +688,14 @@ lifetime parameter.
632
688
You could also write ` select() ` using all named lifetime parameters,
633
689
which might look like:
634
690
635
- ~~~
691
+ ~~~ {.xfail-test}
692
+ # type point = {x: float, y: float}; // as before
693
+ # type size = {w: float, h: float}; // as before
694
+ # enum shape {
695
+ # circle(point, float), // origin, radius
696
+ # rectangle(point, size) // upper-left, dimensions
697
+ # }
698
+ # fn compute_area(shape: &shape) -> float { 0f }
636
699
fn select<T>(shape: &tmp/shape, threshold: float,
637
700
a: &r/T, b: &r/T) -> &r/T {
638
701
if compute_area(shape) > threshold {a} else {b}
@@ -658,7 +721,7 @@ a unique box found in an aliasable, mutable location, only now we’ve
658
721
replaced the ` ... ` with some specific code:
659
722
660
723
~~~
661
- fn example5a(x: @{mut f: ~{g: int}}, ...) -> int {
724
+ fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
662
725
let y = &x.f.g; // Unsafe
663
726
*y + 1
664
727
}
@@ -676,8 +739,9 @@ fn add_one(x: &int) -> int { *x + 1 }
676
739
677
740
We can now update ` example5a() ` to use ` add_one() ` :
678
741
679
- ~~~
680
- fn example5a(x: @{mut f: ~{g: int}}, ...) -> int {
742
+ ~~~ {.xfail-test}
743
+ # fn add_one(x: &int) -> int { *x + 1 }
744
+ fn example5a(x: @{mut f: ~{g: int}} ...) -> int {
681
745
let y = &x.f.g;
682
746
add_one(y) // Error reported here
683
747
}
0 commit comments