tutorial: Remove all references to 'records'. Misc
This commit is contained in:
parent
e4148932fc
commit
2891f5abe3
3 changed files with 41 additions and 32 deletions
|
@ -29,10 +29,10 @@ a limit duration. Borrowed pointers never claim any kind of ownership
|
||||||
over the data that they point at: instead, they are used for cases
|
over the data that they point at: instead, they are used for cases
|
||||||
where you like to make use of data for a short time.
|
where you like to make use of data for a short time.
|
||||||
|
|
||||||
As an example, consider a simple record type `point`:
|
As an example, consider a simple struct type `point`:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
type point = {x: float, y: float};
|
struct point {x: float, y: float}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
We can use this simple definition to allocate points in many ways. For
|
We can use this simple definition to allocate points in many ways. For
|
||||||
|
@ -82,7 +82,7 @@ compute_distance(shared_box, unique_box);
|
||||||
|
|
||||||
Here the `&` operator is used to take the address of the variable
|
Here the `&` operator is used to take the address of the variable
|
||||||
`on_the_stack`; this is because `on_the_stack` has the type `point`
|
`on_the_stack`; this is because `on_the_stack` has the type `point`
|
||||||
(that is, a record value) and we have to take its address to get a
|
(that is, a struct value) and we have to take its address to get a
|
||||||
value. We also call this _borrowing_ the local variable
|
value. We also call this _borrowing_ the local variable
|
||||||
`on_the_stack`, because we are created an alias: that is, another
|
`on_the_stack`, because we are created an alias: that is, another
|
||||||
route to the same data.
|
route to the same data.
|
||||||
|
@ -325,15 +325,18 @@ which has been freed.
|
||||||
In fact, the compiler can apply this same kind of reasoning can be
|
In fact, the compiler can apply this same kind of reasoning can be
|
||||||
applied to any memory which is _(uniquely) owned by the stack
|
applied to any memory which is _(uniquely) owned by the stack
|
||||||
frame_. So we could modify the previous example to introduce
|
frame_. So we could modify the previous example to introduce
|
||||||
additional unique pointers and records, and the compiler will still be
|
additional unique pointers and structs, and the compiler will still be
|
||||||
able to detect possible mutations:
|
able to detect possible mutations:
|
||||||
|
|
||||||
~~~ {.xfail-test}
|
~~~ {.xfail-test}
|
||||||
fn example3() -> int {
|
fn example3() -> int {
|
||||||
let mut x = ~{mut f: ~{g: 3}};
|
struct R { g: int }
|
||||||
|
struct S { mut f: ~R }
|
||||||
|
|
||||||
|
let mut x = ~S {mut f: ~R {g: 3}};
|
||||||
let y = &x.f.g;
|
let y = &x.f.g;
|
||||||
x = ~{mut f: ~{g: 4}}; // Error reported here.
|
x = ~S {mut f: ~R {g: 4}}; // Error reported here.
|
||||||
x.f = ~{g: 5}; // Error reported here.
|
x.f = ~R {g: 5}; // Error reported here.
|
||||||
*y
|
*y
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
@ -504,7 +507,7 @@ Stack Memory
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
As you can see, the `size` pointer would not be pointing at a `float` and
|
As you can see, the `size` pointer would not be pointing at a `float` and
|
||||||
not a record. This is not good.
|
not a struct. This is not good.
|
||||||
|
|
||||||
So, in fact, for every `ref` binding, the compiler will impose the
|
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 unique
|
same rules as the ones we saw for borrowing the interior of a unique
|
||||||
|
@ -559,14 +562,14 @@ defined by the caller.
|
||||||
|
|
||||||
In any case, whatever the lifetime L is, the pointer produced by
|
In any case, whatever the lifetime L is, the pointer produced by
|
||||||
`&p.x` always has the same lifetime as `p` itself, as a pointer to a
|
`&p.x` always has the same lifetime as `p` itself, as a pointer to a
|
||||||
field of a record is valid as long as the record is valid. Therefore,
|
field of a struct is valid as long as the struct is valid. Therefore,
|
||||||
the compiler is satisfied with the function `get_x()`.
|
the compiler is satisfied with the function `get_x()`.
|
||||||
|
|
||||||
To drill in this point, let’s look at a variation on the example, this
|
To drill in this point, let’s look at a variation on the example, this
|
||||||
time one which does not compile:
|
time one which does not compile:
|
||||||
|
|
||||||
~~~ {.xfail-test}
|
~~~ {.xfail-test}
|
||||||
type point = {x: float, y: float};
|
struct point {x: float, y: float}
|
||||||
fn get_x_sh(p: @point) -> &float {
|
fn get_x_sh(p: @point) -> &float {
|
||||||
&p.x // Error reported here
|
&p.x // Error reported here
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ vector.
|
||||||
## Passing structures
|
## Passing structures
|
||||||
|
|
||||||
C functions often take pointers to structs as arguments. Since Rust
|
C functions often take pointers to structs as arguments. Since Rust
|
||||||
records are binary-compatible with C structs, Rust programs can call
|
structs are binary-compatible with C structs, Rust programs can call
|
||||||
such functions directly.
|
such functions directly.
|
||||||
|
|
||||||
This program uses the POSIX function `gettimeofday` to get a
|
This program uses the POSIX function `gettimeofday` to get a
|
||||||
|
@ -215,14 +215,20 @@ microsecond-resolution timer.
|
||||||
extern mod std;
|
extern mod std;
|
||||||
use libc::c_ulonglong;
|
use libc::c_ulonglong;
|
||||||
|
|
||||||
type timeval = {mut tv_sec: c_ulonglong,
|
struct timeval {
|
||||||
mut tv_usec: c_ulonglong};
|
mut tv_sec: c_ulonglong,
|
||||||
|
mut tv_usec: c_ulonglong
|
||||||
|
}
|
||||||
|
|
||||||
#[nolink]
|
#[nolink]
|
||||||
extern mod lib_c {
|
extern mod lib_c {
|
||||||
fn gettimeofday(tv: *timeval, tz: *()) -> i32;
|
fn gettimeofday(tv: *timeval, tz: *()) -> i32;
|
||||||
}
|
}
|
||||||
fn unix_time_in_microseconds() -> u64 unsafe {
|
fn unix_time_in_microseconds() -> u64 unsafe {
|
||||||
let x = {mut tv_sec: 0 as c_ulonglong, mut tv_usec: 0 as c_ulonglong};
|
let x = timeval {
|
||||||
|
mut tv_sec: 0 as c_ulonglong,
|
||||||
|
mut tv_usec: 0 as c_ulonglong
|
||||||
|
};
|
||||||
lib_c::gettimeofday(ptr::addr_of(x), ptr::null());
|
lib_c::gettimeofday(ptr::addr_of(x), ptr::null());
|
||||||
return (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64);
|
return (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64);
|
||||||
}
|
}
|
||||||
|
@ -234,8 +240,8 @@ The `#[nolink]` attribute indicates that there's no foreign library to
|
||||||
link in. The standard C library is already linked with Rust programs.
|
link in. The standard C library is already linked with Rust programs.
|
||||||
|
|
||||||
A `timeval`, in C, is a struct with two 32-bit integers. Thus, we
|
A `timeval`, in C, is a struct with two 32-bit integers. Thus, we
|
||||||
define a record type with the same contents, and declare
|
define a struct type with the same contents, and declare
|
||||||
`gettimeofday` to take a pointer to such a record.
|
`gettimeofday` to take a pointer to such a struct.
|
||||||
|
|
||||||
The second argument to `gettimeofday` (the time zone) is not used by
|
The second argument to `gettimeofday` (the time zone) is not used by
|
||||||
this program, so it simply declares it to be a pointer to the nil
|
this program, so it simply declares it to be a pointer to the nil
|
||||||
|
|
|
@ -713,16 +713,16 @@ enum Shape {
|
||||||
}
|
}
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
A value of this type is either a Circle, in which case it contains a
|
A value of this type is either a `Circle`, in which case it contains a
|
||||||
point struct and a float, or a Rectangle, in which case it contains
|
`Point` struct and a float, or a `Rectangle`, in which case it contains
|
||||||
two point records. The run-time representation of such a value
|
two `Point` structs. The run-time representation of such a value
|
||||||
includes an identifier of the actual form that it holds, much like the
|
includes an identifier of the actual form that it holds, much like the
|
||||||
'tagged union' pattern in C, but with better ergonomics.
|
'tagged union' pattern in C, but with better ergonomics.
|
||||||
|
|
||||||
The above declaration will define a type `shape` that can be used to
|
The above declaration will define a type `Shape` that can be used to
|
||||||
refer to such shapes, and two functions, `circle` and `rectangle`,
|
refer to such shapes, and two functions, `Circle` and `Rectangle`,
|
||||||
which can be used to construct values of the type (taking arguments of
|
which can be used to construct values of the type (taking arguments of
|
||||||
the specified types). So `circle({x: 0f, y: 0f}, 10f)` is the way to
|
the specified types). So `Circle(Point {x: 0f, y: 0f}, 10f)` is the way to
|
||||||
create a new circle.
|
create a new circle.
|
||||||
|
|
||||||
Enum variants need not have type parameters. This, for example, is
|
Enum variants need not have type parameters. This, for example, is
|
||||||
|
@ -820,7 +820,7 @@ fn point_from_direction(dir: Direction) -> Point {
|
||||||
|
|
||||||
## Tuples
|
## Tuples
|
||||||
|
|
||||||
Tuples in Rust behave exactly like records, except that their fields
|
Tuples in Rust behave exactly like structs, except that their fields
|
||||||
do not have names (and can thus not be accessed with dot notation).
|
do not have names (and can thus not be accessed with dot notation).
|
||||||
Tuples can have any arity except for 0 or 1 (though you may consider
|
Tuples can have any arity except for 0 or 1 (though you may consider
|
||||||
nil, `()`, as the empty tuple if you like).
|
nil, `()`, as the empty tuple if you like).
|
||||||
|
@ -1006,16 +1006,16 @@ of each is key to using Rust effectively.
|
||||||
|
|
||||||
# Boxes and pointers
|
# Boxes and pointers
|
||||||
|
|
||||||
In contrast to a lot of modern languages, aggregate types like records
|
In contrast to a lot of modern languages, aggregate types like structs
|
||||||
and enums are _not_ represented as pointers to allocated memory in
|
and enums are _not_ represented as pointers to allocated memory in
|
||||||
Rust. They are, as in C and C++, represented directly. This means that
|
Rust. They are, as in C and C++, represented directly. This means that
|
||||||
if you `let x = {x: 1f, y: 1f};`, you are creating a record on the
|
if you `let x = Point {x: 1f, y: 1f};`, you are creating a struct on the
|
||||||
stack. If you then copy it into a data structure, the whole record is
|
stack. If you then copy it into a data structure, the whole struct is
|
||||||
copied, not just a pointer.
|
copied, not just a pointer.
|
||||||
|
|
||||||
For small records like `point`, this is usually more efficient than
|
For small structs like `Point`, this is usually more efficient than
|
||||||
allocating memory and going through a pointer. But for big records, or
|
allocating memory and going through a pointer. But for big structs, or
|
||||||
records with mutable fields, it can be useful to have a single copy on
|
those with mutable fields, it can be useful to have a single copy on
|
||||||
the heap, and refer to that through a pointer.
|
the heap, and refer to that through a pointer.
|
||||||
|
|
||||||
Rust supports several types of pointers. The safe pointer types are
|
Rust supports several types of pointers. The safe pointer types are
|
||||||
|
@ -1191,8 +1191,8 @@ compute_distance(shared_box, unique_box);
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Here the `&` operator is used to take the address of the variable
|
Here the `&` operator is used to take the address of the variable
|
||||||
`on_the_stack`; this is because `on_the_stack` has the type `point`
|
`on_the_stack`; this is because `on_the_stack` has the type `Point`
|
||||||
(that is, a record value) and we have to take its address to get a
|
(that is, a struct value) and we have to take its address to get a
|
||||||
value. We also call this _borrowing_ the local variable
|
value. We also call this _borrowing_ the local variable
|
||||||
`on_the_stack`, because we are created an alias: that is, another
|
`on_the_stack`, because we are created an alias: that is, another
|
||||||
route to the same data.
|
route to the same data.
|
||||||
|
@ -1517,7 +1517,7 @@ fn each(v: &[int], op: fn(v: &int)) {
|
||||||
The reason we pass in a *pointer* to an integer rather than the
|
The reason we pass in a *pointer* to an integer rather than the
|
||||||
integer itself is that this is how the actual `each()` function for
|
integer itself is that this is how the actual `each()` function for
|
||||||
vectors works. Using a pointer means that the function can be used
|
vectors works. Using a pointer means that the function can be used
|
||||||
for vectors of any type, even large records that would be impractical
|
for vectors of any type, even large structs that would be impractical
|
||||||
to copy out of the vector on each iteration. As a caller, if we use a
|
to copy out of the vector on each iteration. As a caller, if we use a
|
||||||
closure to provide the final operator argument, we can write it in a
|
closure to provide the final operator argument, we can write it in a
|
||||||
way that has a pleasant, block-like structure.
|
way that has a pleasant, block-like structure.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue