librustc: Remove ~EXPR, ~TYPE, and ~PAT from the language, except
for `~str`/`~[]`. Note that `~self` still remains, since I forgot to add support for `Box<self>` before the snapshot. How to update your code: * Instead of `~EXPR`, you should write `box EXPR`. * Instead of `~TYPE`, you should write `Box<Type>`. * Instead of `~PATTERN`, you should write `box PATTERN`. [breaking-change]
This commit is contained in:
parent
24f6f26e63
commit
090040bf40
495 changed files with 2252 additions and 1897 deletions
|
|
@ -293,7 +293,7 @@ extern {
|
|||
|
||||
fn main() {
|
||||
// Create the object that will be referenced in the callback
|
||||
let mut rust_object = ~RustObject{ a: 5 };
|
||||
let mut rust_object = box RustObject { a: 5 };
|
||||
|
||||
unsafe {
|
||||
register_callback(&mut *rust_object, callback);
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ point, but allocated in a different place:
|
|||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
||||
let managed_box : @Point = @Point {x: 5.0, y: 1.0};
|
||||
let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
|
||||
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
||||
let managed_box : @Point = @Point {x: 5.0, y: 1.0};
|
||||
let owned_box : Box<Point> = box Point {x: 7.0, y: 9.0};
|
||||
~~~
|
||||
|
||||
Suppose we wanted to write a procedure that computed the distance between any
|
||||
|
|
@ -72,9 +72,9 @@ Now we can call `compute_distance()` in various ways:
|
|||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
||||
# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
|
||||
# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};
|
||||
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
||||
# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
|
||||
# let owned_box : Box<Point> = box Point{x: 7.0, y: 9.0};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&on_the_stack, managed_box);
|
||||
compute_distance(managed_box, owned_box);
|
||||
|
|
@ -151,12 +151,12 @@ Now, as before, we can define rectangles in a few different ways:
|
|||
# struct Point {x: f64, y: f64}
|
||||
# struct Size {w: f64, h: f64} // as before
|
||||
# struct Rectangle {origin: Point, size: Size}
|
||||
let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_owned = box Rectangle {origin: Point {x: 5.0, y: 6.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
~~~
|
||||
|
||||
In each case, we can extract out individual subcomponents with the `&`
|
||||
|
|
@ -168,7 +168,7 @@ operator. For example, I could write:
|
|||
# struct Rectangle {origin: Point, size: Size}
|
||||
# let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# let rect_owned = box Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&rect_stack.origin, &rect_managed.origin);
|
||||
~~~
|
||||
|
|
@ -276,12 +276,12 @@ the following function is legal:
|
|||
# fn some_condition() -> bool { true }
|
||||
# struct Foo { f: int }
|
||||
fn example3() -> int {
|
||||
let mut x = ~Foo {f: 3};
|
||||
let mut x = box Foo {f: 3};
|
||||
if some_condition() {
|
||||
let y = &x.f; // -+ L
|
||||
return *y; // |
|
||||
} // -+
|
||||
x = ~Foo {f: 4};
|
||||
x = box Foo {f: 4};
|
||||
// ...
|
||||
# return 0;
|
||||
}
|
||||
|
|
@ -301,9 +301,9 @@ rejected by the compiler):
|
|||
|
||||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
let mut x = ~X {f: 3};
|
||||
let mut x = box X {f: 3};
|
||||
let y = &x.f;
|
||||
x = ~X {f: 4}; // Error reported here.
|
||||
x = box X {f: 4}; // Error reported here.
|
||||
*y
|
||||
}
|
||||
~~~
|
||||
|
|
@ -314,13 +314,13 @@ memory immediately before the re-assignment of `x`:
|
|||
~~~ {.notrust}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +----------+
|
||||
| ~{f:int} | ----+
|
||||
y +----------+ |
|
||||
| &int | ----+
|
||||
+----------+ | +---------+
|
||||
+--> | f: 3 |
|
||||
+---------+
|
||||
x +-------------+
|
||||
| box {f:int} | ----+
|
||||
y +-------------+ |
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | f: 3 |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Once the reassignment occurs, the memory will look like this:
|
||||
|
|
@ -328,13 +328,13 @@ Once the reassignment occurs, the memory will look like this:
|
|||
~~~ {.notrust}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +----------+ +---------+
|
||||
| ~{f:int} | -------> | f: 4 |
|
||||
y +----------+ +---------+
|
||||
| &int | ----+
|
||||
+----------+ | +---------+
|
||||
+--> | (freed) |
|
||||
+---------+
|
||||
x +-------------+ +---------+
|
||||
| box {f:int} | -------> | f: 4 |
|
||||
y +-------------+ +---------+
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | (freed) |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Here you can see that the variable `y` still points at the old box,
|
||||
|
|
@ -349,12 +349,12 @@ mutations:
|
|||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
struct R { g: int }
|
||||
struct S { f: ~R }
|
||||
struct S { f: Box<R> }
|
||||
|
||||
let mut x = ~S {f: ~R {g: 3}};
|
||||
let mut x = box S {f: box R {g: 3}};
|
||||
let y = &x.f.g;
|
||||
x = ~S {f: ~R {g: 4}}; // Error reported here.
|
||||
x.f = ~R {g: 5}; // Error reported here.
|
||||
x = box S {f: box R {g: 4}}; // Error reported here.
|
||||
x.f = box R {g: 5}; // Error reported here.
|
||||
*y
|
||||
}
|
||||
~~~
|
||||
|
|
|
|||
|
|
@ -182,13 +182,14 @@ trait. Therefore, unboxed traits don't make any sense, and aren't allowed.
|
|||
Sometimes, you need a recursive data structure. The simplest is known as a 'cons list':
|
||||
|
||||
~~~rust
|
||||
|
||||
enum List<T> {
|
||||
Nil,
|
||||
Cons(T, ~List<T>),
|
||||
Cons(T, Box<List<T>>),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let list: List<int> = Cons(1, ~Cons(2, ~Cons(3, ~Nil)));
|
||||
let list: List<int> = Cons(1, box Cons(2, box Cons(3, box Nil)));
|
||||
println!("{:?}", list);
|
||||
}
|
||||
~~~
|
||||
|
|
@ -196,7 +197,7 @@ fn main() {
|
|||
This prints:
|
||||
|
||||
~~~ {.notrust}
|
||||
Cons(1, ~Cons(2, ~Cons(3, ~Nil)))
|
||||
Cons(1, box Cons(2, box Cons(3, box Nil)))
|
||||
~~~
|
||||
|
||||
The inner lists _must_ be an owned pointer, because we can't know how many
|
||||
|
|
@ -237,7 +238,7 @@ struct Point {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let a = ~Point { x: 10, y: 20 };
|
||||
let a = box Point { x: 10, y: 20 };
|
||||
spawn(proc() {
|
||||
println!("{}", a.x);
|
||||
});
|
||||
|
|
@ -268,7 +269,7 @@ struct Point {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let a = ~Point { x: 10, y: 20 };
|
||||
let a = box Point { x: 10, y: 20 };
|
||||
let b = a;
|
||||
println!("{}", b.x);
|
||||
println!("{}", a.x);
|
||||
|
|
@ -285,7 +286,7 @@ note: in expansion of format_args!
|
|||
<std-macros>:158:27: 158:81 note: expansion site
|
||||
<std-macros>:157:5: 159:6 note: in expansion of println!
|
||||
test.rs:10:5: 10:25 note: expansion site
|
||||
test.rs:8:9: 8:10 note: `a` moved here because it has type `~Point`, which is moved by default (use `ref` to override)
|
||||
test.rs:8:9: 8:10 note: `a` moved here because it has type `Box<Point>`, which is moved by default (use `ref` to override)
|
||||
test.rs:8 let b = a;
|
||||
^
|
||||
~~~
|
||||
|
|
@ -345,8 +346,8 @@ fn compute_distance(p1: &Point, p2: &Point) -> f32 {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let origin = @Point { x: 0.0, y: 0.0 };
|
||||
let p1 = ~Point { x: 5.0, y: 3.0 };
|
||||
let origin = @Point { x: 0.0, y: 0.0 };
|
||||
let p1 = box Point { x: 5.0, y: 3.0 };
|
||||
|
||||
println!("{:?}", compute_distance(origin, p1));
|
||||
}
|
||||
|
|
@ -381,7 +382,7 @@ duration a 'lifetime'. Let's try a more complex example:
|
|||
|
||||
~~~rust
|
||||
fn main() {
|
||||
let mut x = ~5;
|
||||
let mut x = box 5;
|
||||
if *x < 10 {
|
||||
let y = &x;
|
||||
println!("Oh no: {:?}", y);
|
||||
|
|
@ -398,7 +399,7 @@ mutated, and therefore, lets us pass. This wouldn't work:
|
|||
|
||||
~~~rust{.ignore}
|
||||
fn main() {
|
||||
let mut x = ~5;
|
||||
let mut x = box 5;
|
||||
if *x < 10 {
|
||||
let y = &x;
|
||||
*x -= 1;
|
||||
|
|
@ -437,12 +438,12 @@ is best.
|
|||
What does that mean? Don't do this:
|
||||
|
||||
~~~rust
|
||||
fn foo(x: ~int) -> ~int {
|
||||
return ~*x;
|
||||
fn foo(x: Box<int>) -> Box<int> {
|
||||
return box *x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = ~5;
|
||||
let x = box 5;
|
||||
let y = foo(x);
|
||||
}
|
||||
~~~
|
||||
|
|
@ -450,13 +451,13 @@ fn main() {
|
|||
Do this:
|
||||
|
||||
~~~rust
|
||||
fn foo(x: ~int) -> int {
|
||||
fn foo(x: Box<int>) -> int {
|
||||
return *x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = ~5;
|
||||
let y = ~foo(x);
|
||||
let x = box 5;
|
||||
let y = box foo(x);
|
||||
}
|
||||
~~~
|
||||
|
||||
|
|
@ -464,12 +465,12 @@ This gives you flexibility, without sacrificing performance. For example, this w
|
|||
also work:
|
||||
|
||||
~~~rust
|
||||
fn foo(x: ~int) -> int {
|
||||
fn foo(x: Box<int>) -> int {
|
||||
return *x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = ~5;
|
||||
let x = box 5;
|
||||
let y = @foo(x);
|
||||
}
|
||||
~~~
|
||||
|
|
|
|||
|
|
@ -258,10 +258,10 @@ impl<T: Send> Drop for Unique<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// A comparison between the built-in ~ and this reimplementation
|
||||
// A comparison between the built-in `Box` and this reimplementation
|
||||
fn main() {
|
||||
{
|
||||
let mut x = ~5;
|
||||
let mut x = box 5;
|
||||
*x = 10;
|
||||
} // `x` is freed here
|
||||
|
||||
|
|
|
|||
|
|
@ -127,12 +127,13 @@ That's a great example for stack memory,
|
|||
but what about heap memory?
|
||||
Rust has a second kind of pointer,
|
||||
an 'owned box',
|
||||
that you can create with a `~`.
|
||||
that you can create with the `box` operator.
|
||||
Check it out:
|
||||
|
||||
```
|
||||
fn dangling() -> ~int {
|
||||
let i = ~1234;
|
||||
|
||||
fn dangling() -> Box<int> {
|
||||
let i = box 1234;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ fn add_one() -> int {
|
|||
```
|
||||
|
||||
Now instead of a stack allocated `1234`,
|
||||
we have a heap allocated `~1234`.
|
||||
we have a heap allocated `box 1234`.
|
||||
Whereas `&` borrows a pointer to existing memory,
|
||||
creating an owned box allocates memory on the heap and places a value in it,
|
||||
giving you the sole pointer to that memory.
|
||||
|
|
@ -151,7 +152,7 @@ You can roughly compare these two lines:
|
|||
|
||||
```
|
||||
// Rust
|
||||
let i = ~1234;
|
||||
let i = box 1234;
|
||||
```
|
||||
|
||||
```notrust
|
||||
|
|
|
|||
|
|
@ -1393,7 +1393,7 @@ to pointers to the trait name, used as a type.
|
|||
# trait Shape { }
|
||||
# impl Shape for int { }
|
||||
# let mycircle = 0;
|
||||
let myshape: ~Shape = ~mycircle as ~Shape;
|
||||
let myshape: Box<Shape> = box mycircle as Box<Shape>;
|
||||
~~~~
|
||||
|
||||
The resulting value is a managed box containing the value that was cast,
|
||||
|
|
@ -3041,19 +3041,19 @@ stands for a *single* data field, whereas a wildcard `..` stands for *all* the
|
|||
fields of a particular variant. For example:
|
||||
|
||||
~~~~
|
||||
enum List<X> { Nil, Cons(X, ~List<X>) }
|
||||
enum List<X> { Nil, Cons(X, Box<List<X>>) }
|
||||
|
||||
let x: List<int> = Cons(10, ~Cons(11, ~Nil));
|
||||
let x: List<int> = Cons(10, box Cons(11, box Nil));
|
||||
|
||||
match x {
|
||||
Cons(_, ~Nil) => fail!("singleton list"),
|
||||
Cons(..) => return,
|
||||
Nil => fail!("empty list")
|
||||
Cons(_, box Nil) => fail!("singleton list"),
|
||||
Cons(..) => return,
|
||||
Nil => fail!("empty list")
|
||||
}
|
||||
~~~~
|
||||
|
||||
The first pattern matches lists constructed by applying `Cons` to any head
|
||||
value, and a tail value of `~Nil`. The second pattern matches _any_ list
|
||||
value, and a tail value of `box Nil`. The second pattern matches _any_ list
|
||||
constructed with `Cons`, ignoring the values of its arguments. The difference
|
||||
between `_` and `..` is that the pattern `C(_)` is only type-correct if `C` has
|
||||
exactly one argument, while the pattern `C(..)` is type-correct for any enum
|
||||
|
|
@ -3103,12 +3103,12 @@ An example of a `match` expression:
|
|||
# fn process_pair(a: int, b: int) { }
|
||||
# fn process_ten() { }
|
||||
|
||||
enum List<X> { Nil, Cons(X, ~List<X>) }
|
||||
enum List<X> { Nil, Cons(X, Box<List<X>>) }
|
||||
|
||||
let x: List<int> = Cons(10, ~Cons(11, ~Nil));
|
||||
let x: List<int> = Cons(10, box Cons(11, box Nil));
|
||||
|
||||
match x {
|
||||
Cons(a, ~Cons(b, _)) => {
|
||||
Cons(a, box Cons(b, _)) => {
|
||||
process_pair(a,b);
|
||||
}
|
||||
Cons(10, _) => {
|
||||
|
|
@ -3135,17 +3135,17 @@ Subpatterns can also be bound to variables by the use of the syntax
|
|||
For example:
|
||||
|
||||
~~~~
|
||||
enum List { Nil, Cons(uint, ~List) }
|
||||
enum List { Nil, Cons(uint, Box<List>) }
|
||||
|
||||
fn is_sorted(list: &List) -> bool {
|
||||
match *list {
|
||||
Nil | Cons(_, ~Nil) => true,
|
||||
Cons(x, ref r @ ~Cons(y, _)) => (x <= y) && is_sorted(*r)
|
||||
Nil | Cons(_, box Nil) => true,
|
||||
Cons(x, ref r @ box Cons(y, _)) => (x <= y) && is_sorted(*r)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = Cons(6, ~Cons(7, ~Cons(42, ~Nil)));
|
||||
let a = Cons(6, box Cons(7, box Cons(42, box Nil)));
|
||||
assert!(is_sorted(&a));
|
||||
}
|
||||
|
||||
|
|
@ -3411,10 +3411,10 @@ An example of a *recursive* type and its use:
|
|||
~~~~
|
||||
enum List<T> {
|
||||
Nil,
|
||||
Cons(T, ~List<T>)
|
||||
Cons(T, Box<List<T>>)
|
||||
}
|
||||
|
||||
let a: List<int> = Cons(7, ~Cons(13, ~Nil));
|
||||
let a: List<int> = Cons(7, box Cons(13, box Nil));
|
||||
~~~~
|
||||
|
||||
### Pointer types
|
||||
|
|
@ -3563,12 +3563,12 @@ impl Printable for int {
|
|||
fn to_string(&self) -> ~str { self.to_str() }
|
||||
}
|
||||
|
||||
fn print(a: ~Printable) {
|
||||
fn print(a: Box<Printable>) {
|
||||
println!("{}", a.to_string());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print(~10 as ~Printable);
|
||||
print(box 10 as Box<Printable>);
|
||||
}
|
||||
~~~~
|
||||
|
||||
|
|
@ -3755,7 +3755,7 @@ mutable slot by prefixing them with `mut` (similar to regular arguments):
|
|||
~~~
|
||||
trait Changer {
|
||||
fn change(mut self) -> Self;
|
||||
fn modify(mut ~self) -> ~Self;
|
||||
fn modify(mut ~self) -> Box<Self>;
|
||||
}
|
||||
~~~
|
||||
|
||||
|
|
@ -3768,12 +3768,14 @@ initialized; this is enforced by the compiler.
|
|||
### Owned boxes
|
||||
|
||||
An _owned box_ is a reference to a heap allocation holding another value, which is constructed
|
||||
by the prefix *tilde* sigil `~`.
|
||||
by the prefix operator `box`. When the standard library is in use, the type of an owned box is
|
||||
`std::owned::Box<T>`.
|
||||
|
||||
An example of an owned box type and value:
|
||||
|
||||
~~~~
|
||||
let x: ~int = ~10;
|
||||
|
||||
let x: Box<int> = box 10;
|
||||
~~~~
|
||||
|
||||
Owned box values exist in 1:1 correspondence with their heap allocation
|
||||
|
|
@ -3781,7 +3783,7 @@ copying an owned box value makes a shallow copy of the pointer
|
|||
Rust will consider a shallow copy of an owned box to move ownership of the value. After a value has been moved, the source location cannot be used unless it is reinitialized.
|
||||
|
||||
~~~~
|
||||
let x: ~int = ~10;
|
||||
let x: Box<int> = box 10;
|
||||
let y = x;
|
||||
// attempting to use `x` will result in an error here
|
||||
~~~~
|
||||
|
|
|
|||
|
|
@ -911,12 +911,12 @@ Objects are never accessible after their destructor has been called, so no
|
|||
dynamic failures are possible from accessing freed resources. When a task
|
||||
fails, destructors of all objects in the task are called.
|
||||
|
||||
The `~` sigil represents a unique handle for a memory allocation on the heap:
|
||||
The `box` operator performs memory allocation on the heap:
|
||||
|
||||
~~~~
|
||||
{
|
||||
// an integer allocated on the heap
|
||||
let y = ~10;
|
||||
let y = box 10;
|
||||
}
|
||||
// the destructor frees the heap memory as soon as `y` goes out of scope
|
||||
~~~~
|
||||
|
|
@ -938,17 +938,17 @@ and destroy the contained object when they go out of scope.
|
|||
|
||||
~~~~
|
||||
// the struct owns the objects contained in the `x` and `y` fields
|
||||
struct Foo { x: int, y: ~int }
|
||||
struct Foo { x: int, y: Box<int> }
|
||||
|
||||
{
|
||||
// `a` is the owner of the struct, and thus the owner of the struct's fields
|
||||
let a = Foo { x: 5, y: ~10 };
|
||||
let a = Foo { x: 5, y: box 10 };
|
||||
}
|
||||
// when `a` goes out of scope, the destructor for the `~int` in the struct's
|
||||
// field is called
|
||||
|
||||
// `b` is mutable, and the mutability is inherited by the objects it owns
|
||||
let mut b = Foo { x: 5, y: ~10 };
|
||||
let mut b = Foo { x: 5, y: box 10 };
|
||||
b.x = 10;
|
||||
~~~~
|
||||
|
||||
|
|
@ -1021,13 +1021,15 @@ Our previous attempt at defining the `List` type included an `u32` and a `List`
|
|||
directly inside `Cons`, making it at least as big as the sum of both types. The
|
||||
type was invalid because the size was infinite!
|
||||
|
||||
An *owned box* (`~`) uses a dynamic memory allocation to provide the invariant
|
||||
of always being the size of a pointer, regardless of the contained type. This
|
||||
can be leveraged to create a valid `List` definition:
|
||||
An *owned box* (`Box`, located in the `std::owned` module) uses a dynamic memory
|
||||
allocation to provide the invariant of always being the size of a pointer,
|
||||
regardless of the contained type. This can be leveraged to create a valid `List`
|
||||
definition:
|
||||
|
||||
~~~
|
||||
|
||||
enum List {
|
||||
Cons(u32, ~List),
|
||||
Cons(u32, Box<List>),
|
||||
Nil
|
||||
}
|
||||
~~~
|
||||
|
|
@ -1040,10 +1042,10 @@ Consider an instance of our `List` type:
|
|||
|
||||
~~~
|
||||
# enum List {
|
||||
# Cons(u32, ~List),
|
||||
# Cons(u32, Box<List>),
|
||||
# Nil
|
||||
# }
|
||||
let list = Cons(1, ~Cons(2, ~Cons(3, ~Nil)));
|
||||
let list = Cons(1, box Cons(2, box Cons(3, box Nil)));
|
||||
~~~
|
||||
|
||||
It represents an owned tree of values, inheriting mutability down the tree and
|
||||
|
|
@ -1054,7 +1056,7 @@ box, while the owner holds onto a pointer to it:
|
|||
~~~ {.notrust}
|
||||
List box List box List box List box
|
||||
+--------------+ +--------------+ +--------------+ +----------+
|
||||
list -> | Cons | 1 | ~ | -> | Cons | 2 | ~ | -> | Cons | 3 | ~ | -> | Nil |
|
||||
list -> | Cons | 1 | | -> | Cons | 2 | | -> | Cons | 3 | | -> | Nil |
|
||||
+--------------+ +--------------+ +--------------+ +----------+
|
||||
~~~
|
||||
|
||||
|
|
@ -1074,10 +1076,10 @@ the box rather than doing an implicit heap allocation.
|
|||
|
||||
~~~
|
||||
# enum List {
|
||||
# Cons(u32, ~List),
|
||||
# Cons(u32, Box<List>),
|
||||
# Nil
|
||||
# }
|
||||
let xs = Cons(1, ~Cons(2, ~Cons(3, ~Nil)));
|
||||
let xs = Cons(1, box Cons(2, box Cons(3, box Nil)));
|
||||
let ys = xs; // copies `Cons(u32, pointer)` shallowly
|
||||
~~~
|
||||
|
||||
|
|
@ -1087,7 +1089,7 @@ location cannot be used unless it is reinitialized.
|
|||
|
||||
~~~
|
||||
# enum List {
|
||||
# Cons(u32, ~List),
|
||||
# Cons(u32, Box<List>),
|
||||
# Nil
|
||||
# }
|
||||
let mut xs = Nil;
|
||||
|
|
@ -1107,7 +1109,7 @@ as it is only called a single time.
|
|||
Avoiding a move can be done with the library-defined `clone` method:
|
||||
|
||||
~~~~
|
||||
let x = ~5;
|
||||
let x = box 5;
|
||||
let y = x.clone(); // `y` is a newly allocated box
|
||||
let z = x; // no new memory allocated, `x` can no longer be used
|
||||
~~~~
|
||||
|
|
@ -1118,11 +1120,11 @@ our `List` type. Traits will be explained in detail [later](#traits).
|
|||
~~~{.ignore}
|
||||
#[deriving(Clone)]
|
||||
enum List {
|
||||
Cons(u32, ~List),
|
||||
Cons(u32, Box<List>),
|
||||
Nil
|
||||
}
|
||||
|
||||
let x = Cons(5, ~Nil);
|
||||
let x = Cons(5, box Nil);
|
||||
let y = x.clone();
|
||||
|
||||
// `x` can still be used!
|
||||
|
|
@ -1135,7 +1137,7 @@ let z = x;
|
|||
The mutability of a value may be changed by moving it to a new owner:
|
||||
|
||||
~~~~
|
||||
let r = ~13;
|
||||
let r = box 13;
|
||||
let mut s = r; // box becomes mutable
|
||||
*s += 1;
|
||||
let t = s; // box becomes immutable
|
||||
|
|
@ -1146,12 +1148,12 @@ advantage of moves:
|
|||
|
||||
~~~
|
||||
enum List {
|
||||
Cons(u32, ~List),
|
||||
Cons(u32, Box<List>),
|
||||
Nil
|
||||
}
|
||||
|
||||
fn prepend(xs: List, value: u32) -> List {
|
||||
Cons(value, ~xs)
|
||||
Cons(value, box xs)
|
||||
}
|
||||
|
||||
let mut xs = Nil;
|
||||
|
|
@ -1186,7 +1188,7 @@ by-value. A recursive definition of equality using references is as follows:
|
|||
|
||||
~~~
|
||||
# enum List {
|
||||
# Cons(u32, ~List),
|
||||
# Cons(u32, Box<List>),
|
||||
# Nil
|
||||
# }
|
||||
fn eq(xs: &List, ys: &List) -> bool {
|
||||
|
|
@ -1195,15 +1197,15 @@ fn eq(xs: &List, ys: &List) -> bool {
|
|||
// If we have reached the end of both lists, they are equal.
|
||||
(&Nil, &Nil) => true,
|
||||
// If the current elements of both lists are equal, keep going.
|
||||
(&Cons(x, ~ref next_xs), &Cons(y, ~ref next_ys))
|
||||
(&Cons(x, box ref next_xs), &Cons(y, box ref next_ys))
|
||||
if x == y => eq(next_xs, next_ys),
|
||||
// If the current elements are not equal, the lists are not equal.
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
let xs = Cons(5, ~Cons(10, ~Nil));
|
||||
let ys = Cons(5, ~Cons(10, ~Nil));
|
||||
let xs = Cons(5, box Cons(10, box Nil));
|
||||
let ys = Cons(5, box Cons(10, box Nil));
|
||||
assert!(eq(&xs, &ys));
|
||||
~~~
|
||||
|
||||
|
|
@ -1223,7 +1225,7 @@ The `u32` in the previous definition can be substituted with a type parameter:
|
|||
|
||||
~~~
|
||||
enum List<T> {
|
||||
Cons(T, ~List<T>),
|
||||
Cons(T, Box<List<T>>),
|
||||
Nil
|
||||
}
|
||||
~~~
|
||||
|
|
@ -1233,11 +1235,11 @@ definition has to be updated too:
|
|||
|
||||
~~~
|
||||
# enum List<T> {
|
||||
# Cons(T, ~List<T>),
|
||||
# Cons(T, Box<List<T>>),
|
||||
# Nil
|
||||
# }
|
||||
fn prepend<T>(xs: List<T>, value: T) -> List<T> {
|
||||
Cons(value, ~xs)
|
||||
Cons(value, box xs)
|
||||
}
|
||||
~~~
|
||||
|
||||
|
|
@ -1248,11 +1250,11 @@ Using the generic `List<T>` works much like before, thanks to type inference:
|
|||
|
||||
~~~
|
||||
# enum List<T> {
|
||||
# Cons(T, ~List<T>),
|
||||
# Cons(T, Box<List<T>>),
|
||||
# Nil
|
||||
# }
|
||||
# fn prepend<T>(xs: List<T>, value: T) -> List<T> {
|
||||
# Cons(value, ~xs)
|
||||
# Cons(value, box xs)
|
||||
# }
|
||||
let mut xs = Nil; // Unknown type! This is a `List<T>`, but `T` can be anything.
|
||||
xs = prepend(xs, 10); // Here the compiler infers `xs`'s type as `List<int>`.
|
||||
|
|
@ -1265,11 +1267,11 @@ equivalent to the following type-annotated code:
|
|||
|
||||
~~~
|
||||
# enum List<T> {
|
||||
# Cons(T, ~List<T>),
|
||||
# Cons(T, Box<List<T>>),
|
||||
# Nil
|
||||
# }
|
||||
# fn prepend<T>(xs: List<T>, value: T) -> List<T> {
|
||||
# Cons(value, ~xs)
|
||||
# Cons(value, box xs)
|
||||
# }
|
||||
let mut xs: List<int> = Nil::<int>;
|
||||
xs = prepend::<int>(xs, 10);
|
||||
|
|
@ -1293,7 +1295,7 @@ Two more `ref` annotations need to be added to avoid attempting to move out the
|
|||
|
||||
~~~
|
||||
# enum List<T> {
|
||||
# Cons(T, ~List<T>),
|
||||
# Cons(T, Box<List<T>>),
|
||||
# Nil
|
||||
# }
|
||||
fn eq<T: Eq>(xs: &List<T>, ys: &List<T>) -> bool {
|
||||
|
|
@ -1302,15 +1304,15 @@ fn eq<T: Eq>(xs: &List<T>, ys: &List<T>) -> bool {
|
|||
// If we have reached the end of both lists, they are equal.
|
||||
(&Nil, &Nil) => true,
|
||||
// If the current elements of both lists are equal, keep going.
|
||||
(&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys))
|
||||
(&Cons(ref x, box ref next_xs), &Cons(ref y, box ref next_ys))
|
||||
if x == y => eq(next_xs, next_ys),
|
||||
// If the current elements are not equal, the lists are not equal.
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
let xs = Cons('c', ~Cons('a', ~Cons('t', ~Nil)));
|
||||
let ys = Cons('c', ~Cons('a', ~Cons('t', ~Nil)));
|
||||
let xs = Cons('c', box Cons('a', box Cons('t', box Nil)));
|
||||
let ys = Cons('c', box Cons('a', box Cons('t', box Nil)));
|
||||
assert!(eq(&xs, &ys));
|
||||
~~~
|
||||
|
||||
|
|
@ -1321,7 +1323,7 @@ on.
|
|||
|
||||
~~~
|
||||
# enum List<T> {
|
||||
# Cons(T, ~List<T>),
|
||||
# Cons(T, Box<List<T>>),
|
||||
# Nil
|
||||
# }
|
||||
impl<T: Eq> Eq for List<T> {
|
||||
|
|
@ -1331,7 +1333,7 @@ impl<T: Eq> Eq for List<T> {
|
|||
// If we have reached the end of both lists, they are equal.
|
||||
(&Nil, &Nil) => true,
|
||||
// If the current elements of both lists are equal, keep going.
|
||||
(&Cons(ref x, ~ref next_xs), &Cons(ref y, ~ref next_ys))
|
||||
(&Cons(ref x, box ref next_xs), &Cons(ref y, box ref next_ys))
|
||||
if x == y => next_xs == next_ys,
|
||||
// If the current elements are not equal, the lists are not equal.
|
||||
_ => false
|
||||
|
|
@ -1339,8 +1341,8 @@ impl<T: Eq> Eq for List<T> {
|
|||
}
|
||||
}
|
||||
|
||||
let xs = Cons(5, ~Cons(10, ~Nil));
|
||||
let ys = Cons(5, ~Cons(10, ~Nil));
|
||||
let xs = Cons(5, box Cons(10, box Nil));
|
||||
let ys = Cons(5, box Cons(10, box Nil));
|
||||
// The methods below are part of the Eq trait,
|
||||
// which we implemented on our linked list.
|
||||
assert!(xs.eq(&ys));
|
||||
|
|
@ -1373,7 +1375,7 @@ fn foo() -> (u64, u64, u64, u64, u64, u64) {
|
|||
(5, 5, 5, 5, 5, 5)
|
||||
}
|
||||
|
||||
let x = ~foo(); // allocates a `~` box, and writes the integers directly to it
|
||||
let x = box foo(); // allocates a box, and writes the integers directly to it
|
||||
~~~~
|
||||
|
||||
Beyond the properties granted by the size, an owned box behaves as a regular
|
||||
|
|
@ -1384,8 +1386,8 @@ let x = 5; // immutable
|
|||
let mut y = 5; // mutable
|
||||
y += 2;
|
||||
|
||||
let x = ~5; // immutable
|
||||
let mut y = ~5; // mutable
|
||||
let x = box 5; // immutable
|
||||
let mut y = box 5; // mutable
|
||||
*y += 2; // the `*` operator is needed to access the contained value
|
||||
~~~~
|
||||
|
||||
|
|
@ -1413,8 +1415,8 @@ contains a point, but allocated in a different location:
|
|||
|
||||
~~~
|
||||
# struct Point { x: f64, y: f64 }
|
||||
let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
|
||||
let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };
|
||||
let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
|
||||
let owned_box : Box<Point> = box Point { x: 7.0, y: 9.0 };
|
||||
~~~
|
||||
|
||||
Suppose we want to write a procedure that computes the distance
|
||||
|
|
@ -1438,8 +1440,8 @@ Now we can call `compute_distance()` in various ways:
|
|||
|
||||
~~~
|
||||
# struct Point{ x: f64, y: f64 };
|
||||
# let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
|
||||
# let owned_box : ~Point = ~Point { x: 7.0, y: 9.0 };
|
||||
# let on_the_stack : Point = Point { x: 3.0, y: 4.0 };
|
||||
# let owned_box : Box<Point> = box Point { x: 7.0, y: 9.0 };
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&on_the_stack, owned_box);
|
||||
~~~
|
||||
|
|
@ -1453,7 +1455,7 @@ route to the same data.
|
|||
|
||||
In the case of `owned_box`, however, no
|
||||
explicit action is necessary. The compiler will automatically convert
|
||||
a box `~point` to a reference like
|
||||
a box `box point` to a reference like
|
||||
`&point`. This is another form of borrowing; in this case, the
|
||||
contents of the owned box are being lent out.
|
||||
|
||||
|
|
@ -1492,7 +1494,7 @@ Rust uses the unary star operator (`*`) to access the contents of a
|
|||
box or pointer, similarly to C.
|
||||
|
||||
~~~
|
||||
let owned = ~10;
|
||||
let owned = box 10;
|
||||
let borrowed = &20;
|
||||
|
||||
let sum = *owned + *borrowed;
|
||||
|
|
@ -1503,7 +1505,7 @@ assignments. Such an assignment modifies the value that the pointer
|
|||
points to.
|
||||
|
||||
~~~
|
||||
let mut owned = ~10;
|
||||
let mut owned = box 10;
|
||||
|
||||
let mut value = 20;
|
||||
let borrowed = &mut value;
|
||||
|
|
@ -1520,8 +1522,8 @@ can sometimes make code awkward and parenthesis-filled.
|
|||
# struct Point { x: f64, y: f64 }
|
||||
# enum Shape { Rectangle(Point, Point) }
|
||||
# impl Shape { fn area(&self) -> int { 0 } }
|
||||
let start = ~Point { x: 10.0, y: 20.0 };
|
||||
let end = ~Point { x: (*start).x + 100.0, y: (*start).y + 100.0 };
|
||||
let start = box Point { x: 10.0, y: 20.0 };
|
||||
let end = box Point { x: (*start).x + 100.0, y: (*start).y + 100.0 };
|
||||
let rect = &Rectangle(*start, *end);
|
||||
let area = (*rect).area();
|
||||
~~~
|
||||
|
|
@ -1534,8 +1536,8 @@ dot), so in most cases, explicitly dereferencing the receiver is not necessary.
|
|||
# struct Point { x: f64, y: f64 }
|
||||
# enum Shape { Rectangle(Point, Point) }
|
||||
# impl Shape { fn area(&self) -> int { 0 } }
|
||||
let start = ~Point { x: 10.0, y: 20.0 };
|
||||
let end = ~Point { x: start.x + 100.0, y: start.y + 100.0 };
|
||||
let start = box Point { x: 10.0, y: 20.0 };
|
||||
let end = box Point { x: start.x + 100.0, y: start.y + 100.0 };
|
||||
let rect = &Rectangle(*start, *end);
|
||||
let area = rect.area();
|
||||
~~~
|
||||
|
|
@ -1546,7 +1548,7 @@ something silly like
|
|||
|
||||
~~~
|
||||
# struct Point { x: f64, y: f64 }
|
||||
let point = &~Point { x: 10.0, y: 20.0 };
|
||||
let point = &box Point { x: 10.0, y: 20.0 };
|
||||
println!("{:f}", point.x);
|
||||
~~~
|
||||
|
||||
|
|
@ -1944,7 +1946,7 @@ impl Shape {
|
|||
let s = Circle(Point { x: 1.0, y: 2.0 }, 3.0);
|
||||
|
||||
(&s).draw_reference();
|
||||
(~s).draw_owned();
|
||||
(box s).draw_owned();
|
||||
s.draw_value();
|
||||
~~~
|
||||
|
||||
|
|
@ -1969,7 +1971,7 @@ to a reference.
|
|||
// As with typical function arguments, owned pointers
|
||||
// are automatically converted to references
|
||||
|
||||
(~s).draw_reference();
|
||||
(box s).draw_reference();
|
||||
|
||||
// Unlike typical function arguments, the self value will
|
||||
// automatically be referenced ...
|
||||
|
|
@ -1979,7 +1981,7 @@ s.draw_reference();
|
|||
(& &s).draw_reference();
|
||||
|
||||
// ... and dereferenced and borrowed
|
||||
(&~s).draw_reference();
|
||||
(&box s).draw_reference();
|
||||
~~~
|
||||
|
||||
Implementations may also define standalone (sometimes called "static")
|
||||
|
|
@ -2433,7 +2435,7 @@ an _object_.
|
|||
|
||||
~~~~
|
||||
# trait Drawable { fn draw(&self); }
|
||||
fn draw_all(shapes: &[~Drawable]) {
|
||||
fn draw_all(shapes: &[Box<Drawable>]) {
|
||||
for shape in shapes.iter() { shape.draw(); }
|
||||
}
|
||||
~~~~
|
||||
|
|
@ -2448,14 +2450,14 @@ to an object:
|
|||
# trait Drawable { fn draw(&self); }
|
||||
# fn new_circle() -> Circle { 1 }
|
||||
# fn new_rectangle() -> Rectangle { true }
|
||||
# fn draw_all(shapes: &[~Drawable]) {}
|
||||
# fn draw_all(shapes: &[Box<Drawable>]) {}
|
||||
|
||||
impl Drawable for Circle { fn draw(&self) { /* ... */ } }
|
||||
impl Drawable for Rectangle { fn draw(&self) { /* ... */ } }
|
||||
|
||||
let c: ~Circle = ~new_circle();
|
||||
let r: ~Rectangle = ~new_rectangle();
|
||||
draw_all([c as ~Drawable, r as ~Drawable]);
|
||||
let c: Box<Circle> = box new_circle();
|
||||
let r: Box<Rectangle> = box new_rectangle();
|
||||
draw_all([c as Box<Drawable>, r as Box<Drawable>]);
|
||||
~~~~
|
||||
|
||||
We omit the code for `new_circle` and `new_rectangle`; imagine that
|
||||
|
|
@ -2464,7 +2466,7 @@ that, like strings and vectors, objects have dynamic size and may
|
|||
only be referred to via one of the pointer types.
|
||||
Other pointer types work as well.
|
||||
Casts to traits may only be done with compatible pointers so,
|
||||
for example, an `&Circle` may not be cast to an `~Drawable`.
|
||||
for example, an `&Circle` may not be cast to a `Box<Drawable>`.
|
||||
|
||||
~~~
|
||||
# type Circle = int; type Rectangle = int;
|
||||
|
|
@ -2473,7 +2475,7 @@ for example, an `&Circle` may not be cast to an `~Drawable`.
|
|||
# fn new_circle() -> int { 1 }
|
||||
# fn new_rectangle() -> int { 2 }
|
||||
// An owned object
|
||||
let owny: ~Drawable = ~new_circle() as ~Drawable;
|
||||
let owny: Box<Drawable> = box new_circle() as Box<Drawable>;
|
||||
// A borrowed object
|
||||
let stacky: &Drawable = &new_circle() as &Drawable;
|
||||
~~~
|
||||
|
|
@ -2497,7 +2499,7 @@ valid types:
|
|||
trait Foo {}
|
||||
trait Bar<T> {}
|
||||
|
||||
fn sendable_foo(f: ~Foo:Send) { /* ... */ }
|
||||
fn sendable_foo(f: Box<Foo:Send>) { /* ... */ }
|
||||
fn shareable_bar<T: Share>(b: &Bar<T>: Share) { /* ... */ }
|
||||
~~~
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue