2
2
3
3
# Introduction
4
4
5
- Borrowed pointers are one of the more flexible and powerful tools
6
- available in Rust. A borrowed pointer can be used to point anywhere:
7
- into the managed and exchange heaps , into the stack, and even into the
8
- interior of another data structure. With regard to flexibility, it is
9
- comparable to a C pointer or C++ reference. However, unlike C and C++,
10
- the Rust compiler includes special checks that ensure that borrowed
11
- pointers are being used safely. Another advantage of borrowed pointers
12
- is that they are invisible to the garbage collector, so working with
13
- borrowed pointers helps keep things efficient .
14
-
15
- Despite the fact that they are completely safe, at runtime, a borrowed
16
- pointer is “just a pointer”. They introduce zero overhead. All safety
17
- checks are done at compilation time.
5
+ Borrowed pointers are one of the more flexible and powerful tools available in
6
+ Rust. A borrowed pointer can point anywhere: into the managed or exchange
7
+ heap , into the stack, and even into the interior of another data structure. A
8
+ borrowed pointer is as flexible as a C pointer or C++ reference. However,
9
+ unlike C and C++ compilers, the Rust compiler includes special static checks
10
+ that ensure that programs use borrowed pointers safely. Another advantage of
11
+ borrowed pointers is that they are invisible to the garbage collector, so
12
+ working with borrowed pointers helps reduce the overhead of automatic memory
13
+ management .
14
+
15
+ Despite their complete safety, a borrowed pointer's representation at runtime
16
+ is the same as that of an ordinary pointer in a C program. They introduce zero
17
+ overhead. The compiler does all safety checks at compile time.
18
18
19
19
Although borrowed pointers have rather elaborate theoretical
20
20
underpinnings (region pointers), the core concepts will be familiar to
21
- anyone who worked with C or C++. Therefore, the best way to explain
21
+ anyone who has worked with C or C++. Therefore, the best way to explain
22
22
how they are used—and their limitations—is probably just to work
23
23
through several examples.
24
24
25
25
# By example
26
26
27
- Borrowed pointers are called borrowed because they are only valid for
28
- a limit duration. Borrowed pointers never claim any kind of ownership
29
- over the data that they point at : instead, they are used for cases
30
- where you like to make use of data for a short time.
27
+ Borrowed pointers are called * borrowed* because they are only valid for
28
+ a limited duration. Borrowed pointers never claim any kind of ownership
29
+ over the data that they point to : instead, they are used for cases
30
+ where you would like to use data for a short time.
31
31
32
32
As an example, consider a simple struct type ` Point ` :
33
33
34
34
~~~
35
35
struct Point {x: float, y: float}
36
36
~~~
37
37
38
- We can use this simple definition to allocate points in many ways. For
38
+ We can use this simple definition to allocate points in many different ways. For
39
39
example, in this code, each of these three local variables contains a
40
40
point, but allocated in a different place:
41
41
@@ -46,17 +46,17 @@ let shared_box : @Point = @Point {x: 5.0, y: 1.0};
46
46
let unique_box : ~Point = ~Point {x: 7.0, y: 9.0};
47
47
~~~
48
48
49
- Suppose we wanted to write a procedure that computed the distance
50
- between any two points, no matter where they were stored. For example,
51
- we might like to compute the distance between ` on_the_stack ` and
52
- ` shared_box ` , or between ` shared_box ` and ` unique_box ` . One option is
53
- to define a function that takes two arguments of type point —that is,
54
- it takes the points by value. But this will cause the points to be
55
- copied when we call the function . For points, this is probably not so
56
- bad, but often copies are expensive or, worse, if there are mutable
57
- fields, they can change the semantics of your program. So we’ d like to
58
- define a function that takes the points by pointer. We can use
59
- borrowed pointers to do this:
49
+ Suppose we wanted to write a procedure that computed the distance between any
50
+ two points, no matter where they were stored. For example, we might like to
51
+ compute the distance between ` on_the_stack ` and ` shared_box ` , or between
52
+ ` shared_box ` and ` unique_box ` . One option is to define a function that takes
53
+ two arguments of type ` Point ` —that is, it takes the points by value. But we
54
+ define it this way, calling the function will cause the points to be
55
+ copied. For points, this is probably not so bad, but often copies are
56
+ expensive. Worse, if the data type contains mutable fields, copying can change
57
+ the semantics of your program in unexpected ways . So we' d like to define a
58
+ function that takes the points by pointer. We can use borrowed pointers to do
59
+ this:
60
60
61
61
~~~
62
62
# struct Point {x: float, y: float}
@@ -80,28 +80,28 @@ compute_distance(&on_the_stack, shared_box);
80
80
compute_distance(shared_box, unique_box);
81
81
~~~
82
82
83
- Here the ` & ` operator is used to take the address of the variable
83
+ Here, the ` & ` operator takes the address of the variable
84
84
` on_the_stack ` ; this is because ` on_the_stack ` has the type ` Point `
85
85
(that is, a struct value) and we have to take its address to get a
86
86
value. We also call this _ borrowing_ the local variable
87
- ` on_the_stack ` , because we are created an alias: that is, another
88
- route to the same data.
89
-
90
- In the case of the boxes ` shared_box ` and ` unique_box ` , however, no
91
- explicit action is necessary . The compiler will automatically convert
92
- a box like ` @Point ` or ` ~Point ` to a borrowed pointer like
93
- ` &Point ` . This is another form of borrowing; in this case, the
94
- contents of the shared/ unique box is being lent out .
95
-
96
- Whenever a value is borrowed , there are some limitations on what you
97
- can do with the original. For example, if the contents of a variable
98
- have been lent out, you cannot send that variable to another task, nor
99
- will you be permitted to take actions that might cause the borrowed
100
- value to be freed or to change its type (I’ll get into what kinds of
101
- actions those are shortly). This rule should make intuitive sense: you
102
- must wait for a borrowed value to be returned (that is, for the
103
- borrowed pointer to go out of scope) before you can make full use of
104
- it again.
87
+ ` on_the_stack ` , because we have created an alias: that is, another
88
+ name for the same data.
89
+
90
+ In contrast, we can pass the boxes ` shared_box ` and ` unique_box ` to
91
+ ` compute_distance ` directly . The compiler automatically converts a box like
92
+ ` @Point ` or ` ~Point ` to a borrowed pointer like ` &Point ` . This is another form
93
+ of borrowing: in this case, the caller lends the contents of the shared or
94
+ unique box to the callee .
95
+
96
+ Whenever a caller lends data to a callee , there are some limitations on what
97
+ the caller can do with the original. For example, if the contents of a
98
+ variable have been lent out, you cannot send that variable to another task. In
99
+ addition, the compiler will reject any code that might cause the borrowed
100
+ value to be freed or overwrite its component fields with values of different
101
+ types (I'll get into what kinds of actions those are shortly). This rule
102
+ should make intuitive sense: you must wait for a borrower to return the value
103
+ that you lent it (that is, wait for the borrowed pointer to go out of scope)
104
+ before you can make full use of it again.
105
105
106
106
# Other uses for the & operator
107
107
0 commit comments