clean up some things
I double checked that everything is here and in the correct order; this fixes things up
This commit is contained in:
parent
c937254357
commit
287a3457bc
|
@ -630,7 +630,7 @@ unsafe fn bump_levels_unsafe2() -> u32 {
|
||||||
Mutable statics have the same restrictions as normal statics, except that the
|
Mutable statics have the same restrictions as normal statics, except that the
|
||||||
type of the value is not required to ascribe to `Sync`.
|
type of the value is not required to ascribe to `Sync`.
|
||||||
|
|
||||||
### `'static` lifetime elision
|
#### `'static` lifetime elision
|
||||||
|
|
||||||
[Unstable] Both constant and static declarations of reference types have
|
[Unstable] Both constant and static declarations of reference types have
|
||||||
*implicit* `'static` lifetimes unless an explicit lifetime is specified. As
|
*implicit* `'static` lifetimes unless an explicit lifetime is specified. As
|
||||||
|
@ -676,3 +676,372 @@ const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
|
||||||
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
|
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
|
||||||
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
|
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Traits
|
||||||
|
|
||||||
|
A _trait_ describes an abstract interface that types can
|
||||||
|
implement. This interface consists of associated items, which come in
|
||||||
|
three varieties:
|
||||||
|
|
||||||
|
- functions
|
||||||
|
- constants
|
||||||
|
- types
|
||||||
|
|
||||||
|
Associated functions whose first parameter is named `self` are called
|
||||||
|
methods and may be invoked using `.` notation (e.g., `x.foo()`).
|
||||||
|
|
||||||
|
All traits define an implicit type parameter `Self` that refers to
|
||||||
|
"the type that is implementing this interface". Traits may also
|
||||||
|
contain additional type parameters. These type parameters (including
|
||||||
|
`Self`) may be constrained by other traits and so forth as usual.
|
||||||
|
|
||||||
|
Trait bounds on `Self` are considered "supertraits". These are
|
||||||
|
required to be acyclic. Supertraits are somewhat different from other
|
||||||
|
constraints in that they affect what methods are available in the
|
||||||
|
vtable when the trait is used as a [trait object](#trait-objects).
|
||||||
|
|
||||||
|
Traits are implemented for specific types through separate
|
||||||
|
[implementations](#implementations).
|
||||||
|
|
||||||
|
Consider the following trait:
|
||||||
|
|
||||||
|
```
|
||||||
|
# type Surface = i32;
|
||||||
|
# type BoundingBox = i32;
|
||||||
|
trait Shape {
|
||||||
|
fn draw(&self, Surface);
|
||||||
|
fn bounding_box(&self) -> BoundingBox;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This defines a trait with two methods. All values that have
|
||||||
|
[implementations](#implementations) of this trait in scope can have their
|
||||||
|
`draw` and `bounding_box` methods called, using `value.bounding_box()`
|
||||||
|
[syntax](#method-call-expressions).
|
||||||
|
|
||||||
|
Traits can include default implementations of methods, as in:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Foo {
|
||||||
|
fn bar(&self);
|
||||||
|
fn baz(&self) { println!("We called baz."); }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here the `baz` method has a default implementation, so types that implement
|
||||||
|
`Foo` need only implement `bar`. It is also possible for implementing types
|
||||||
|
to override a method that has a default implementation.
|
||||||
|
|
||||||
|
Type parameters can be specified for a trait to make it generic. These appear
|
||||||
|
after the trait name, using the same syntax used in [generic
|
||||||
|
functions](#generic-functions).
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Seq<T> {
|
||||||
|
fn len(&self) -> u32;
|
||||||
|
fn elt_at(&self, n: u32) -> T;
|
||||||
|
fn iter<F>(&self, F) where F: Fn(T);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to define associated types for a trait. Consider the
|
||||||
|
following example of a `Container` trait. Notice how the type is available
|
||||||
|
for use in the method signatures:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Container {
|
||||||
|
type E;
|
||||||
|
fn empty() -> Self;
|
||||||
|
fn insert(&mut self, Self::E);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In order for a type to implement this trait, it must not only provide
|
||||||
|
implementations for every method, but it must specify the type `E`. Here's
|
||||||
|
an implementation of `Container` for the standard library type `Vec`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# trait Container {
|
||||||
|
# type E;
|
||||||
|
# fn empty() -> Self;
|
||||||
|
# fn insert(&mut self, Self::E);
|
||||||
|
# }
|
||||||
|
impl<T> Container for Vec<T> {
|
||||||
|
type E = T;
|
||||||
|
fn empty() -> Vec<T> { Vec::new() }
|
||||||
|
fn insert(&mut self, x: T) { self.push(x); }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generic functions may use traits as _bounds_ on their type parameters. This
|
||||||
|
will have two effects:
|
||||||
|
|
||||||
|
- Only types that have the trait may instantiate the parameter.
|
||||||
|
- Within the generic function, the methods of the trait can be
|
||||||
|
called on values that have the parameter's type.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
# type Surface = i32;
|
||||||
|
# trait Shape { fn draw(&self, Surface); }
|
||||||
|
fn draw_twice<T: Shape>(surface: Surface, sh: T) {
|
||||||
|
sh.draw(surface);
|
||||||
|
sh.draw(surface);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Traits also define a [trait object](#trait-objects) with the same
|
||||||
|
name as the trait. Values of this type are created by coercing from a
|
||||||
|
pointer of some specific type to a pointer of trait type. For example,
|
||||||
|
`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly
|
||||||
|
for `Box<T>`). This coercion can either be implicit or
|
||||||
|
[explicit](#type-cast-expressions). Here is an example of an explicit
|
||||||
|
coercion:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Shape { }
|
||||||
|
impl Shape for i32 { }
|
||||||
|
let mycircle = 0i32;
|
||||||
|
let myshape: Box<Shape> = Box::new(mycircle) as Box<Shape>;
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting value is a box containing the value that was cast, along with
|
||||||
|
information that identifies the methods of the implementation that was used.
|
||||||
|
Values with a trait type can have [methods called](#method-call-expressions) on
|
||||||
|
them, for any method in the trait, and can be used to instantiate type
|
||||||
|
parameters that are bounded by the trait.
|
||||||
|
|
||||||
|
Trait methods may be static, which means that they lack a `self` argument.
|
||||||
|
This means that they can only be called with function call syntax (`f(x)`) and
|
||||||
|
not method call syntax (`obj.f()`). The way to refer to the name of a static
|
||||||
|
method is to qualify it with the trait name, treating the trait name like a
|
||||||
|
module. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Num {
|
||||||
|
fn from_i32(n: i32) -> Self;
|
||||||
|
}
|
||||||
|
impl Num for f64 {
|
||||||
|
fn from_i32(n: i32) -> f64 { n as f64 }
|
||||||
|
}
|
||||||
|
let x: f64 = Num::from_i32(42);
|
||||||
|
```
|
||||||
|
|
||||||
|
Traits may inherit from other traits. Consider the following example:
|
||||||
|
|
||||||
|
```
|
||||||
|
trait Shape { fn area(&self) -> f64; }
|
||||||
|
trait Circle : Shape { fn radius(&self) -> f64; }
|
||||||
|
```
|
||||||
|
|
||||||
|
The syntax `Circle : Shape` means that types that implement `Circle` must also
|
||||||
|
have an implementation for `Shape`. Multiple supertraits are separated by `+`,
|
||||||
|
`trait Circle : Shape + PartialEq { }`. In an implementation of `Circle` for a
|
||||||
|
given type `T`, methods can refer to `Shape` methods, since the typechecker
|
||||||
|
checks that any type with an implementation of `Circle` also has an
|
||||||
|
implementation of `Shape`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
trait Shape { fn area(&self) -> f64; }
|
||||||
|
trait Circle : Shape { fn radius(&self) -> f64; }
|
||||||
|
impl Shape for Foo {
|
||||||
|
fn area(&self) -> f64 {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Circle for Foo {
|
||||||
|
fn radius(&self) -> f64 {
|
||||||
|
println!("calling area: {}", self.area());
|
||||||
|
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = Foo;
|
||||||
|
c.radius();
|
||||||
|
```
|
||||||
|
|
||||||
|
In type-parameterized functions, methods of the supertrait may be called on
|
||||||
|
values of subtrait-bound type parameters. Referring to the previous example of
|
||||||
|
`trait Circle : Shape`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# trait Shape { fn area(&self) -> f64; }
|
||||||
|
# trait Circle : Shape { fn radius(&self) -> f64; }
|
||||||
|
fn radius_times_area<T: Circle>(c: T) -> f64 {
|
||||||
|
// `c` is both a Circle and a Shape
|
||||||
|
c.radius() * c.area()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Likewise, supertrait methods may also be called on trait objects.
|
||||||
|
|
||||||
|
```{.ignore}
|
||||||
|
# trait Shape { fn area(&self) -> f64; }
|
||||||
|
# trait Circle : Shape { fn radius(&self) -> f64; }
|
||||||
|
# impl Shape for i32 { fn area(&self) -> f64 { 0.0 } }
|
||||||
|
# impl Circle for i32 { fn radius(&self) -> f64 { 0.0 } }
|
||||||
|
# let mycircle = 0i32;
|
||||||
|
let mycircle = Box::new(mycircle) as Box<Circle>;
|
||||||
|
let nonsense = mycircle.radius() * mycircle.area();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementations
|
||||||
|
|
||||||
|
An _implementation_ is an item that implements a [trait](#traits) for a
|
||||||
|
specific type.
|
||||||
|
|
||||||
|
Implementations are defined with the keyword `impl`.
|
||||||
|
|
||||||
|
```
|
||||||
|
# #[derive(Copy, Clone)]
|
||||||
|
# struct Point {x: f64, y: f64};
|
||||||
|
# type Surface = i32;
|
||||||
|
# struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
|
||||||
|
# trait Shape { fn draw(&self, Surface); fn bounding_box(&self) -> BoundingBox; }
|
||||||
|
# fn do_draw_circle(s: Surface, c: Circle) { }
|
||||||
|
struct Circle {
|
||||||
|
radius: f64,
|
||||||
|
center: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for Circle {}
|
||||||
|
|
||||||
|
impl Clone for Circle {
|
||||||
|
fn clone(&self) -> Circle { *self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape for Circle {
|
||||||
|
fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
|
||||||
|
fn bounding_box(&self) -> BoundingBox {
|
||||||
|
let r = self.radius;
|
||||||
|
BoundingBox {
|
||||||
|
x: self.center.x - r,
|
||||||
|
y: self.center.y - r,
|
||||||
|
width: 2.0 * r,
|
||||||
|
height: 2.0 * r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is possible to define an implementation without referring to a trait. The
|
||||||
|
methods in such an implementation can only be used as direct calls on the values
|
||||||
|
of the type that the implementation targets. In such an implementation, the
|
||||||
|
trait type and `for` after `impl` are omitted. Such implementations are limited
|
||||||
|
to nominal types (enums, structs, trait objects), and the implementation must
|
||||||
|
appear in the same crate as the `self` type:
|
||||||
|
|
||||||
|
```
|
||||||
|
struct Point {x: i32, y: i32}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
fn log(&self) {
|
||||||
|
println!("Point is at ({}, {})", self.x, self.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let my_point = Point {x: 10, y:11};
|
||||||
|
my_point.log();
|
||||||
|
```
|
||||||
|
|
||||||
|
When a trait _is_ specified in an `impl`, all methods declared as part of the
|
||||||
|
trait must be implemented, with matching types and type parameter counts.
|
||||||
|
|
||||||
|
An implementation can take type parameters, which can be different from the
|
||||||
|
type parameters taken by the trait it implements. Implementation parameters
|
||||||
|
are written after the `impl` keyword.
|
||||||
|
|
||||||
|
```
|
||||||
|
# trait Seq<T> { fn dummy(&self, _: T) { } }
|
||||||
|
impl<T> Seq<T> for Vec<T> {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
impl Seq<bool> for u32 {
|
||||||
|
/* Treat the integer as a sequence of bits */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### External blocks
|
||||||
|
|
||||||
|
External blocks form the basis for Rust's foreign function interface.
|
||||||
|
Declarations in an external block describe symbols in external, non-Rust
|
||||||
|
libraries.
|
||||||
|
|
||||||
|
Functions within external blocks are declared in the same way as other Rust
|
||||||
|
functions, with the exception that they may not have a body and are instead
|
||||||
|
terminated by a semicolon.
|
||||||
|
|
||||||
|
Functions within external blocks may be called by Rust code, just like
|
||||||
|
functions defined in Rust. The Rust compiler automatically translates between
|
||||||
|
the Rust ABI and the foreign ABI.
|
||||||
|
|
||||||
|
Functions within external blocks may be variadic by specifying `...` after one
|
||||||
|
or more named arguments in the argument list:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
extern {
|
||||||
|
fn foo(x: i32, ...);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A number of [attributes](#ffi-attributes) control the behavior of external blocks.
|
||||||
|
|
||||||
|
By default external blocks assume that the library they are calling uses the
|
||||||
|
standard C ABI on the specific platform. Other ABIs may be specified using an
|
||||||
|
`abi` string, as shown here:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
// Interface to the Windows API
|
||||||
|
extern "stdcall" { }
|
||||||
|
```
|
||||||
|
|
||||||
|
There are three ABI strings which are cross-platform, and which all compilers
|
||||||
|
are guaranteed to support:
|
||||||
|
|
||||||
|
* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any
|
||||||
|
Rust code.
|
||||||
|
* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default
|
||||||
|
your C compiler supports.
|
||||||
|
* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in
|
||||||
|
which case it's `"stdcall"`, or what you should use to link to the Windows API
|
||||||
|
itself
|
||||||
|
|
||||||
|
There are also some platform-specific ABI strings:
|
||||||
|
|
||||||
|
* `extern "cdecl"` -- The default for x86\_32 C code.
|
||||||
|
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
|
||||||
|
* `extern "win64"` -- The default for C code on x86\_64 Windows.
|
||||||
|
* `extern "sysv64"` -- The default for C code on non-Windows x86\_64.
|
||||||
|
* `extern "aapcs"` -- The default for ARM.
|
||||||
|
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||||
|
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||||
|
* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's
|
||||||
|
`__vectorcall` and clang's `__attribute__((vectorcall))`
|
||||||
|
|
||||||
|
Finally, there are some rustc-specific ABI strings:
|
||||||
|
|
||||||
|
* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics.
|
||||||
|
* `extern "rust-call"` -- The ABI of the Fn::call trait functions.
|
||||||
|
* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for
|
||||||
|
example, `sqrt` -- have this ABI. You should never have to deal with it.
|
||||||
|
|
||||||
|
The `link` attribute allows the name of the library to be specified. When
|
||||||
|
specified the compiler will attempt to link against the native library of the
|
||||||
|
specified name.
|
||||||
|
|
||||||
|
```{.ignore}
|
||||||
|
#[link(name = "crypto")]
|
||||||
|
extern { }
|
||||||
|
```
|
||||||
|
|
||||||
|
The type of a function declared in an extern block is `extern "abi" fn(A1, ...,
|
||||||
|
An) -> R`, where `A1...An` are the declared types of its arguments and `R` is
|
||||||
|
the declared return type.
|
||||||
|
|
||||||
|
It is valid to add the `link` attribute on an empty extern block. You can use
|
||||||
|
this to satisfy the linking requirements of extern blocks elsewhere in your code
|
||||||
|
(including upstream crates) instead of adding the attribute to each extern block.
|
||||||
|
|
|
@ -8,17 +8,3 @@ discipline, exist in the standard library.
|
||||||
|
|
||||||
Allocations in the stack consist of *variables*, and allocations in the heap
|
Allocations in the stack consist of *variables*, and allocations in the heap
|
||||||
consist of *boxes*.
|
consist of *boxes*.
|
||||||
|
|
||||||
## Memory allocation and lifetime
|
|
||||||
|
|
||||||
The _items_ of a program are those functions, modules and types that have their
|
|
||||||
value calculated at compile-time and stored uniquely in the memory image of the
|
|
||||||
rust process. Items are neither dynamically allocated nor freed.
|
|
||||||
|
|
||||||
The _heap_ is a general term that describes boxes. The lifetime of an
|
|
||||||
allocation in the heap depends on the lifetime of the box values pointing to
|
|
||||||
it. Since box values may themselves be passed in and out of frames, or stored
|
|
||||||
in the heap, heap allocations may outlive the frame they are allocated within.
|
|
||||||
An allocation in the heap is guaranteed to reside at a single location in the
|
|
||||||
heap for the whole lifetime of the allocation - it will never be relocated as
|
|
||||||
a result of moving a box value.
|
|
||||||
|
|
|
@ -303,3 +303,14 @@ The representation semantics of floating-point numbers are described in
|
||||||
### Boolean literals
|
### Boolean literals
|
||||||
|
|
||||||
The two values of the boolean type are written `true` and `false`.
|
The two values of the boolean type are written `true` and `false`.
|
||||||
|
|
||||||
|
## Symbols
|
||||||
|
|
||||||
|
Symbols are a general class of printable [tokens](#tokens) that play structural
|
||||||
|
roles in a variety of grammar productions. They are a
|
||||||
|
set of remaining miscellaneous printable tokens that do not
|
||||||
|
otherwise appear as [unary operators](#unary-operator-expressions), [binary
|
||||||
|
operators](#binary-operator-expressions), or [keywords][keywords].
|
||||||
|
They are catalogued in [the Symbols section][symbols] of the Grammar document.
|
||||||
|
|
||||||
|
[symbols]: grammar.html#symbols
|
||||||
|
|
|
@ -9,32 +9,3 @@ Rust:
|
||||||
- Dereferencing a [raw pointer](#pointer-types).
|
- Dereferencing a [raw pointer](#pointer-types).
|
||||||
- Reading or writing a [mutable static variable](#mutable-statics).
|
- Reading or writing a [mutable static variable](#mutable-statics).
|
||||||
- Calling an unsafe function (including an intrinsic or foreign function).
|
- Calling an unsafe function (including an intrinsic or foreign function).
|
||||||
|
|
||||||
## Unsafe functions
|
|
||||||
|
|
||||||
Unsafe functions are functions that are not safe in all contexts and/or for all
|
|
||||||
possible inputs. Such a function must be prefixed with the keyword `unsafe` and
|
|
||||||
can only be called from an `unsafe` block or another `unsafe` function.
|
|
||||||
|
|
||||||
## Unsafe blocks
|
|
||||||
|
|
||||||
A block of code can be prefixed with the `unsafe` keyword, to permit calling
|
|
||||||
`unsafe` functions or dereferencing raw pointers within a safe function.
|
|
||||||
|
|
||||||
When a programmer has sufficient conviction that a sequence of potentially
|
|
||||||
unsafe operations is actually safe, they can encapsulate that sequence (taken
|
|
||||||
as a whole) within an `unsafe` block. The compiler will consider uses of such
|
|
||||||
code safe, in the surrounding context.
|
|
||||||
|
|
||||||
Unsafe blocks are used to wrap foreign libraries, make direct use of hardware
|
|
||||||
or implement features not directly present in the language. For example, Rust
|
|
||||||
provides the language features necessary to implement memory-safe concurrency
|
|
||||||
in the language but the implementation of threads and message passing is in the
|
|
||||||
standard library.
|
|
||||||
|
|
||||||
Rust's type system is a conservative approximation of the dynamic safety
|
|
||||||
requirements, so in some cases there is a performance cost to using safe code.
|
|
||||||
For example, a doubly-linked list is not a tree structure and can only be
|
|
||||||
represented with reference-counted pointers in safe code. By using `unsafe`
|
|
||||||
blocks to represent the reverse links as raw pointers, it can be implemented
|
|
||||||
with only boxes.
|
|
||||||
|
|
Loading…
Reference in New Issue