mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-12 09:57:43 +00:00
auto merge of #21300 : steveklabnik/rust/rollup, r=steveklabnik
manual rollup to fix some conflicts and diagnose why the test is failing...
This commit is contained in:
commit
f4f10dba29
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2014 The Rust Project Developers
|
Copyright (c) 2015 The Rust Project Developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any
|
||||||
person obtaining a copy of this software and associated
|
person obtaining a copy of this software and associated
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
TARGET_CRATES := libc std flate arena term \
|
TARGET_CRATES := libc std flate arena term \
|
||||||
serialize getopts collections test rand \
|
serialize getopts collections test rand \
|
||||||
log regex graphviz core rbml alloc \
|
log regex graphviz core rbml alloc \
|
||||||
unicode
|
unicode rustc_bitflags
|
||||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||||
rustc_trans rustc_back rustc_llvm rustc_privacy
|
rustc_trans rustc_back rustc_llvm rustc_privacy
|
||||||
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
||||||
@ -64,7 +64,8 @@ DEPS_libc := core
|
|||||||
DEPS_unicode := core
|
DEPS_unicode := core
|
||||||
DEPS_alloc := core libc native:jemalloc
|
DEPS_alloc := core libc native:jemalloc
|
||||||
DEPS_std := core libc rand alloc collections unicode \
|
DEPS_std := core libc rand alloc collections unicode \
|
||||||
native:rust_builtin native:backtrace native:rustrt_native
|
native:rust_builtin native:backtrace native:rustrt_native \
|
||||||
|
rustc_bitflags
|
||||||
DEPS_graphviz := std
|
DEPS_graphviz := std
|
||||||
DEPS_syntax := std term serialize log fmt_macros arena libc
|
DEPS_syntax := std term serialize log fmt_macros arena libc
|
||||||
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
||||||
@ -83,6 +84,7 @@ DEPS_rustc_llvm := native:rustllvm libc std
|
|||||||
DEPS_rustc_back := std syntax rustc_llvm flate log libc
|
DEPS_rustc_back := std syntax rustc_llvm flate log libc
|
||||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||||
test
|
test
|
||||||
|
DEPS_rustc_bitflags := core
|
||||||
DEPS_flate := std native:miniz
|
DEPS_flate := std native:miniz
|
||||||
DEPS_arena := std
|
DEPS_arena := std
|
||||||
DEPS_graphviz := std
|
DEPS_graphviz := std
|
||||||
@ -114,6 +116,7 @@ ONLY_RLIB_alloc := 1
|
|||||||
ONLY_RLIB_rand := 1
|
ONLY_RLIB_rand := 1
|
||||||
ONLY_RLIB_collections := 1
|
ONLY_RLIB_collections := 1
|
||||||
ONLY_RLIB_unicode := 1
|
ONLY_RLIB_unicode := 1
|
||||||
|
ONLY_RLIB_rustc_bitflags := 1
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# You should not need to edit below this line
|
# You should not need to edit below this line
|
||||||
|
@ -424,11 +424,11 @@ Let's see an example. This Rust code will not compile:
|
|||||||
use std::thread::Thread;
|
use std::thread::Thread;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut numbers = vec![1i, 2i, 3i];
|
let mut numbers = vec![1is, 2, 3];
|
||||||
|
|
||||||
for i in range(0u, 3u) {
|
for i in 0..3 {
|
||||||
Thread::spawn(move || {
|
Thread::spawn(move || {
|
||||||
for j in range(0, 3) { numbers[j] += 1 }
|
for j in 0..3 { numbers[j] += 1 }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -438,15 +438,15 @@ It gives us this error:
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
6:71 error: capture of moved value: `numbers`
|
6:71 error: capture of moved value: `numbers`
|
||||||
for j in range(0, 3) { numbers[j] += 1 }
|
for j in 0..3 { numbers[j] += 1 }
|
||||||
^~~~~~~
|
^~~~~~~
|
||||||
7:50 note: `numbers` moved into closure environment here
|
7:50 note: `numbers` moved into closure environment here
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
for j in range(0, 3) { numbers[j] += 1 }
|
for j in 0..3 { numbers[j] += 1 }
|
||||||
});
|
});
|
||||||
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
|
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
|
||||||
for j in range(0, 3) { numbers[j] += 1 }
|
for j in 0..3 { numbers[j] += 1 }
|
||||||
^~~~~~~~~~~~~~~
|
^~~~~~~~~~~~~~~
|
||||||
```
|
```
|
||||||
|
|
||||||
It mentions that "numbers moved into closure environment". Because we
|
It mentions that "numbers moved into closure environment". Because we
|
||||||
@ -478,9 +478,9 @@ use std::thread::Thread;
|
|||||||
use std::sync::{Arc,Mutex};
|
use std::sync::{Arc,Mutex};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let numbers = Arc::new(Mutex::new(vec![1i, 2i, 3i]));
|
let numbers = Arc::new(Mutex::new(vec![1is, 2, 3]));
|
||||||
|
|
||||||
for i in range(0u, 3u) {
|
for i in 0..3 {
|
||||||
let number = numbers.clone();
|
let number = numbers.clone();
|
||||||
Thread::spawn(move || {
|
Thread::spawn(move || {
|
||||||
let mut array = number.lock().unwrap();
|
let mut array = number.lock().unwrap();
|
||||||
@ -541,12 +541,12 @@ safety check that makes this an error about moved values:
|
|||||||
use std::thread::Thread;
|
use std::thread::Thread;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let vec = vec![1i, 2, 3];
|
let vec = vec![1is, 2, 3];
|
||||||
|
|
||||||
for i in range(0u, 3) {
|
for i in 0us..3 {
|
||||||
Thread::spawn(move || {
|
Thread::spawn(move || {
|
||||||
println!("{}", vec[i]);
|
println!("{}", vec[i]);
|
||||||
}).detach();
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -557,9 +557,9 @@ you can remove it. As an example, this is a poor way to iterate through
|
|||||||
a vector:
|
a vector:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let vec = vec![1i, 2, 3];
|
let vec = vec![1, 2, 3];
|
||||||
|
|
||||||
for i in range(0u, vec.len()) {
|
for i in 0..vec.len() {
|
||||||
println!("{}", vec[i]);
|
println!("{}", vec[i]);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -569,7 +569,7 @@ that we don't try to access an invalid index. However, we can remove this
|
|||||||
while retaining safety. The answer is iterators:
|
while retaining safety. The answer is iterators:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let vec = vec![1i, 2, 3];
|
let vec = vec![1, 2, 3];
|
||||||
|
|
||||||
for x in vec.iter() {
|
for x in vec.iter() {
|
||||||
println!("{}", x);
|
println!("{}", x);
|
||||||
|
@ -1413,6 +1413,27 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
|
|||||||
In this example, `Cat` is a _struct-like enum variant_,
|
In this example, `Cat` is a _struct-like enum variant_,
|
||||||
whereas `Dog` is simply called an enum variant.
|
whereas `Dog` is simply called an enum variant.
|
||||||
|
|
||||||
|
Enums have a discriminant. You can assign them explicitly:
|
||||||
|
|
||||||
|
```
|
||||||
|
enum Foo {
|
||||||
|
Bar = 123,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a discriminant isn't assigned, they start at zero, and add one for each
|
||||||
|
variant, in order.
|
||||||
|
|
||||||
|
You can cast an enum to get this value:
|
||||||
|
|
||||||
|
```
|
||||||
|
# enum Foo { Bar = 123 }
|
||||||
|
let x = Foo::Bar as u32; // x is now 123u32
|
||||||
|
```
|
||||||
|
|
||||||
|
This only works as long as none of the variants have data attached. If
|
||||||
|
it were `Bar(i32)`, this is disallowed.
|
||||||
|
|
||||||
### Constant items
|
### Constant items
|
||||||
|
|
||||||
```{.ebnf .gram}
|
```{.ebnf .gram}
|
||||||
|
@ -5,7 +5,7 @@ things. The most basic is the *array*, a fixed-size list of elements of the
|
|||||||
same type. By default, arrays are immutable.
|
same type. By default, arrays are immutable.
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let a = [1, 2, 3]; // a: [i32; 3]
|
let a = [1, 2, 3]; // a: [i32; 3]
|
||||||
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
|||||||
|
|
||||||
nums.push(4);
|
nums.push(4);
|
||||||
|
|
||||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||||
```
|
```
|
||||||
|
|
||||||
Vectors have many more useful methods.
|
Vectors have many more useful methods.
|
||||||
@ -82,10 +82,10 @@ arrays:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let a = [0, 1, 2, 3, 4];
|
let a = [0, 1, 2, 3, 4];
|
||||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||||
|
|
||||||
for e in middle.iter() {
|
for e in middle.iter() {
|
||||||
println!("{}", e); // Prints 1, 2, 3
|
println!("{}", e); // Prints 1, 2, 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ arity and contained types.
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut x = (1, 2); // x: (i32, i32)
|
let mut x = (1, 2); // x: (i32, i32)
|
||||||
let y = (2, 3); // y: (i32, i32)
|
let y = (2, 3); // y: (i32, i32)
|
||||||
|
|
||||||
x = y;
|
x = y;
|
||||||
```
|
```
|
||||||
@ -156,7 +156,7 @@ These two will not be equal, even if they have the same values:
|
|||||||
```{rust}
|
```{rust}
|
||||||
# struct Color(i32, i32, i32);
|
# struct Color(i32, i32, i32);
|
||||||
# struct Point(i32, i32, i32);
|
# struct Point(i32, i32, i32);
|
||||||
let black = Color(0, 0, 0);
|
let black = Color(0, 0, 0);
|
||||||
let origin = Point(0, 0, 0);
|
let origin = Point(0, 0, 0);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ enum StringResult {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
Where a `StringResult` is either a `StringResult::StringOK`, with the result of
|
Where a `StringResult` is either a `StringResult::StringOK`, with the result of
|
||||||
a computation, or an `StringResult::ErrorReason` with a `String` explaining
|
a computation, or a `StringResult::ErrorReason` with a `String` explaining
|
||||||
what caused the computation to fail. These kinds of `enum`s are actually very
|
what caused the computation to fail. These kinds of `enum`s are actually very
|
||||||
useful and are even part of the standard library.
|
useful and are even part of the standard library.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Crates and Modules Guide
|
% Crates and Modules
|
||||||
|
|
||||||
When a project starts getting large, it's considered a good software
|
When a project starts getting large, it's considered a good software
|
||||||
engineering practice to split it up into a bunch of smaller pieces, and then
|
engineering practice to split it up into a bunch of smaller pieces, and then
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% Error Handling in Rust
|
% Error Handling
|
||||||
|
|
||||||
> The best-laid plans of mice and men
|
> The best-laid plans of mice and men
|
||||||
> Often go awry
|
> Often go awry
|
||||||
@ -60,12 +60,12 @@ fn probability(_: &Event) -> f64 {
|
|||||||
|
|
||||||
fn descriptive_probability(event: Event) -> &'static str {
|
fn descriptive_probability(event: Event) -> &'static str {
|
||||||
match probability(&event) {
|
match probability(&event) {
|
||||||
1.00 => "certain",
|
1.00 => "certain",
|
||||||
0.00 => "impossible",
|
0.00 => "impossible",
|
||||||
0.00 ... 0.25 => "very unlikely",
|
0.00 ... 0.25 => "very unlikely",
|
||||||
0.25 ... 0.50 => "unlikely",
|
0.25 ... 0.50 => "unlikely",
|
||||||
0.50 ... 0.75 => "likely",
|
0.50 ... 0.75 => "likely",
|
||||||
0.75 ... 1.00 => "very likely",
|
0.75 ... 1.00 => "very likely",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,12 +97,12 @@ fn probability(_: &Event) -> f64 {
|
|||||||
|
|
||||||
fn descriptive_probability(event: Event) -> &'static str {
|
fn descriptive_probability(event: Event) -> &'static str {
|
||||||
match probability(&event) {
|
match probability(&event) {
|
||||||
1.00 => "certain",
|
1.00 => "certain",
|
||||||
0.00 => "impossible",
|
0.00 => "impossible",
|
||||||
0.00 ... 0.25 => "very unlikely",
|
0.00 ... 0.25 => "very unlikely",
|
||||||
0.25 ... 0.50 => "unlikely",
|
0.25 ... 0.50 => "unlikely",
|
||||||
0.50 ... 0.75 => "likely",
|
0.50 ... 0.75 => "likely",
|
||||||
0.75 ... 1.00 => "very likely",
|
0.75 ... 1.00 => "very likely",
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Foreign Function Interface Guide
|
% Foreign Function Interface
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ snappy includes a C interface (documented in
|
|||||||
The following is a minimal example of calling a foreign function which will
|
The following is a minimal example of calling a foreign function which will
|
||||||
compile if snappy is installed:
|
compile if snappy is installed:
|
||||||
|
|
||||||
~~~~no_run
|
```no_run
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use libc::size_t;
|
use libc::size_t;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ fn main() {
|
|||||||
let x = unsafe { snappy_max_compressed_length(100) };
|
let x = unsafe { snappy_max_compressed_length(100) };
|
||||||
println!("max compressed length of a 100 byte buffer: {}", x);
|
println!("max compressed length of a 100 byte buffer: {}", x);
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
The `extern` block is a list of function signatures in a foreign library, in
|
The `extern` block is a list of function signatures in a foreign library, in
|
||||||
this case with the platform's C ABI. The `#[link(...)]` attribute is used to
|
this case with the platform's C ABI. The `#[link(...)]` attribute is used to
|
||||||
@ -44,7 +44,7 @@ keeping the binding correct at runtime.
|
|||||||
|
|
||||||
The `extern` block can be extended to cover the entire snappy API:
|
The `extern` block can be extended to cover the entire snappy API:
|
||||||
|
|
||||||
~~~~no_run
|
```no_run
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use libc::{c_int, size_t};
|
use libc::{c_int, size_t};
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ extern {
|
|||||||
compressed_length: size_t) -> c_int;
|
compressed_length: size_t) -> c_int;
|
||||||
}
|
}
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
# Creating a safe interface
|
# Creating a safe interface
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous
|
|||||||
length is number of elements currently contained, and the capacity is the total size in elements of
|
length is number of elements currently contained, and the capacity is the total size in elements of
|
||||||
the allocated memory. The length is less than or equal to the capacity.
|
the allocated memory. The length is less than or equal to the capacity.
|
||||||
|
|
||||||
~~~~
|
```
|
||||||
# extern crate libc;
|
# extern crate libc;
|
||||||
# use libc::{c_int, size_t};
|
# use libc::{c_int, size_t};
|
||||||
# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 }
|
# unsafe fn snappy_validate_compressed_buffer(_: *const u8, _: size_t) -> c_int { 0 }
|
||||||
@ -89,7 +89,7 @@ pub fn validate_compressed_buffer(src: &[u8]) -> bool {
|
|||||||
snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
|
snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
|
The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
|
||||||
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
|
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
|
||||||
@ -103,7 +103,7 @@ required capacity to hold the compressed output. The vector can then be passed t
|
|||||||
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
|
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
|
||||||
the true length after compression for setting the length.
|
the true length after compression for setting the length.
|
||||||
|
|
||||||
~~~~
|
```
|
||||||
# extern crate libc;
|
# extern crate libc;
|
||||||
# use libc::{size_t, c_int};
|
# use libc::{size_t, c_int};
|
||||||
# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8,
|
# unsafe fn snappy_compress(a: *const u8, b: size_t, c: *mut u8,
|
||||||
@ -116,20 +116,20 @@ pub fn compress(src: &[u8]) -> Vec<u8> {
|
|||||||
let psrc = src.as_ptr();
|
let psrc = src.as_ptr();
|
||||||
|
|
||||||
let mut dstlen = snappy_max_compressed_length(srclen);
|
let mut dstlen = snappy_max_compressed_length(srclen);
|
||||||
let mut dst = Vec::with_capacity(dstlen as uint);
|
let mut dst = Vec::with_capacity(dstlen as usize);
|
||||||
let pdst = dst.as_mut_ptr();
|
let pdst = dst.as_mut_ptr();
|
||||||
|
|
||||||
snappy_compress(psrc, srclen, pdst, &mut dstlen);
|
snappy_compress(psrc, srclen, pdst, &mut dstlen);
|
||||||
dst.set_len(dstlen as uint);
|
dst.set_len(dstlen as usize);
|
||||||
dst
|
dst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
Decompression is similar, because snappy stores the uncompressed size as part of the compression
|
Decompression is similar, because snappy stores the uncompressed size as part of the compression
|
||||||
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
|
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
|
||||||
|
|
||||||
~~~~
|
```
|
||||||
# extern crate libc;
|
# extern crate libc;
|
||||||
# use libc::{size_t, c_int};
|
# use libc::{size_t, c_int};
|
||||||
# unsafe fn snappy_uncompress(compressed: *const u8,
|
# unsafe fn snappy_uncompress(compressed: *const u8,
|
||||||
@ -148,45 +148,22 @@ pub fn uncompress(src: &[u8]) -> Option<Vec<u8>> {
|
|||||||
let mut dstlen: size_t = 0;
|
let mut dstlen: size_t = 0;
|
||||||
snappy_uncompressed_length(psrc, srclen, &mut dstlen);
|
snappy_uncompressed_length(psrc, srclen, &mut dstlen);
|
||||||
|
|
||||||
let mut dst = Vec::with_capacity(dstlen as uint);
|
let mut dst = Vec::with_capacity(dstlen as usize);
|
||||||
let pdst = dst.as_mut_ptr();
|
let pdst = dst.as_mut_ptr();
|
||||||
|
|
||||||
if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
|
if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
|
||||||
dst.set_len(dstlen as uint);
|
dst.set_len(dstlen as usize);
|
||||||
Some(dst)
|
Some(dst)
|
||||||
} else {
|
} else {
|
||||||
None // SNAPPY_INVALID_INPUT
|
None // SNAPPY_INVALID_INPUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
For reference, the examples used here are also available as an [library on
|
For reference, the examples used here are also available as an [library on
|
||||||
GitHub](https://github.com/thestinger/rust-snappy).
|
GitHub](https://github.com/thestinger/rust-snappy).
|
||||||
|
|
||||||
# Stack management
|
|
||||||
|
|
||||||
Rust threads by default run on a *large stack*. This is actually implemented as a
|
|
||||||
reserving a large segment of the address space and then lazily mapping in pages
|
|
||||||
as they are needed. When calling an external C function, the code is invoked on
|
|
||||||
the same stack as the rust stack. This means that there is no extra
|
|
||||||
stack-switching mechanism in place because it is assumed that the large stack
|
|
||||||
for the rust thread is plenty for the C function to have.
|
|
||||||
|
|
||||||
A planned future improvement (not yet implemented at the time of this writing)
|
|
||||||
is to have a guard page at the end of every rust stack. No rust function will
|
|
||||||
hit this guard page (due to Rust's usage of LLVM's `__morestack`). The intention
|
|
||||||
for this unmapped page is to prevent infinite recursion in C from overflowing
|
|
||||||
onto other rust stacks. If the guard page is hit, then the process will be
|
|
||||||
terminated with a message saying that the guard page was hit.
|
|
||||||
|
|
||||||
For normal external function usage, this all means that there shouldn't be any
|
|
||||||
need for any extra effort on a user's perspective. The C stack naturally
|
|
||||||
interleaves with the rust stack, and it's "large enough" for both to
|
|
||||||
interoperate. If, however, it is determined that a larger stack is necessary,
|
|
||||||
there are appropriate functions in the thread spawning API to control the size of
|
|
||||||
the stack of the thread which is spawned.
|
|
||||||
|
|
||||||
# Destructors
|
# Destructors
|
||||||
|
|
||||||
Foreign libraries often hand off ownership of resources to the calling code.
|
Foreign libraries often hand off ownership of resources to the calling code.
|
||||||
@ -208,7 +185,7 @@ A basic example is:
|
|||||||
|
|
||||||
Rust code:
|
Rust code:
|
||||||
|
|
||||||
~~~~no_run
|
```no_run
|
||||||
extern fn callback(a: i32) {
|
extern fn callback(a: i32) {
|
||||||
println!("I'm called from C with value {0}", a);
|
println!("I'm called from C with value {0}", a);
|
||||||
}
|
}
|
||||||
@ -225,11 +202,11 @@ fn main() {
|
|||||||
trigger_callback(); // Triggers the callback
|
trigger_callback(); // Triggers the callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
C code:
|
C code:
|
||||||
|
|
||||||
~~~~c
|
```c
|
||||||
typedef void (*rust_callback)(int32_t);
|
typedef void (*rust_callback)(int32_t);
|
||||||
rust_callback cb;
|
rust_callback cb;
|
||||||
|
|
||||||
@ -241,7 +218,7 @@ int32_t register_callback(rust_callback callback) {
|
|||||||
void trigger_callback() {
|
void trigger_callback() {
|
||||||
cb(7); // Will call callback(7) in Rust
|
cb(7); // Will call callback(7) in Rust
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
In this example Rust's `main()` will call `trigger_callback()` in C,
|
In this example Rust's `main()` will call `trigger_callback()` in C,
|
||||||
which would, in turn, call back to `callback()` in Rust.
|
which would, in turn, call back to `callback()` in Rust.
|
||||||
@ -261,7 +238,7 @@ referenced Rust object.
|
|||||||
|
|
||||||
Rust code:
|
Rust code:
|
||||||
|
|
||||||
~~~~no_run
|
```no_run
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct RustObject {
|
struct RustObject {
|
||||||
a: i32,
|
a: i32,
|
||||||
@ -292,11 +269,11 @@ fn main() {
|
|||||||
trigger_callback();
|
trigger_callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
C code:
|
C code:
|
||||||
|
|
||||||
~~~~c
|
```c
|
||||||
typedef void (*rust_callback)(void*, int32_t);
|
typedef void (*rust_callback)(void*, int32_t);
|
||||||
void* cb_target;
|
void* cb_target;
|
||||||
rust_callback cb;
|
rust_callback cb;
|
||||||
@ -310,7 +287,7 @@ int32_t register_callback(void* callback_target, rust_callback callback) {
|
|||||||
void trigger_callback() {
|
void trigger_callback() {
|
||||||
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
|
cb(cb_target, 7); // Will call callback(&rustObject, 7) in Rust
|
||||||
}
|
}
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
## Asynchronous callbacks
|
## Asynchronous callbacks
|
||||||
|
|
||||||
@ -389,13 +366,13 @@ the `link_args` attribute. This attribute is applied to `extern` blocks and
|
|||||||
specifies raw flags which need to get passed to the linker when producing an
|
specifies raw flags which need to get passed to the linker when producing an
|
||||||
artifact. An example usage would be:
|
artifact. An example usage would be:
|
||||||
|
|
||||||
~~~ no_run
|
``` no_run
|
||||||
#![feature(link_args)]
|
#![feature(link_args)]
|
||||||
|
|
||||||
#[link_args = "-foo -bar -baz"]
|
#[link_args = "-foo -bar -baz"]
|
||||||
extern {}
|
extern {}
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
~~~
|
```
|
||||||
|
|
||||||
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
||||||
because this is not a sanctioned way of performing linking. Right now rustc
|
because this is not a sanctioned way of performing linking. Right now rustc
|
||||||
@ -416,9 +393,9 @@ the compiler that the unsafety does not leak out of the block.
|
|||||||
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
|
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
|
||||||
this:
|
this:
|
||||||
|
|
||||||
~~~~
|
```
|
||||||
unsafe fn kaboom(ptr: *const int) -> int { *ptr }
|
unsafe fn kaboom(ptr: *const int) -> int { *ptr }
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
This function can only be called from an `unsafe` block or another `unsafe` function.
|
This function can only be called from an `unsafe` block or another `unsafe` function.
|
||||||
|
|
||||||
@ -428,7 +405,7 @@ Foreign APIs often export a global variable which could do something like track
|
|||||||
global state. In order to access these variables, you declare them in `extern`
|
global state. In order to access these variables, you declare them in `extern`
|
||||||
blocks with the `static` keyword:
|
blocks with the `static` keyword:
|
||||||
|
|
||||||
~~~no_run
|
```no_run
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
#[link(name = "readline")]
|
#[link(name = "readline")]
|
||||||
@ -440,13 +417,13 @@ fn main() {
|
|||||||
println!("You have readline version {} installed.",
|
println!("You have readline version {} installed.",
|
||||||
rl_readline_version as int);
|
rl_readline_version as int);
|
||||||
}
|
}
|
||||||
~~~
|
```
|
||||||
|
|
||||||
Alternatively, you may need to alter global state provided by a foreign
|
Alternatively, you may need to alter global state provided by a foreign
|
||||||
interface. To do this, statics can be declared with `mut` so rust can mutate
|
interface. To do this, statics can be declared with `mut` so rust can mutate
|
||||||
them.
|
them.
|
||||||
|
|
||||||
~~~no_run
|
```no_run
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
@ -463,7 +440,7 @@ fn main() {
|
|||||||
// get a line, process it
|
// get a line, process it
|
||||||
unsafe { rl_prompt = ptr::null(); }
|
unsafe { rl_prompt = ptr::null(); }
|
||||||
}
|
}
|
||||||
~~~
|
```
|
||||||
|
|
||||||
# Foreign calling conventions
|
# Foreign calling conventions
|
||||||
|
|
||||||
@ -471,7 +448,7 @@ Most foreign code exposes a C ABI, and Rust uses the platform's C calling conven
|
|||||||
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
|
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
|
||||||
conventions. Rust provides a way to tell the compiler which convention to use:
|
conventions. Rust provides a way to tell the compiler which convention to use:
|
||||||
|
|
||||||
~~~~
|
```
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
#[cfg(all(target_os = "win32", target_arch = "x86"))]
|
#[cfg(all(target_os = "win32", target_arch = "x86"))]
|
||||||
@ -481,7 +458,7 @@ extern "stdcall" {
|
|||||||
fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
|
fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
|
||||||
}
|
}
|
||||||
# fn main() { }
|
# fn main() { }
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
This applies to the entire `extern` block. The list of supported ABI constraints
|
This applies to the entire `extern` block. The list of supported ABI constraints
|
||||||
are:
|
are:
|
||||||
@ -541,3 +518,22 @@ with one of the non-nullable types, it is represented as a single pointer,
|
|||||||
and the non-data variant is represented as the null pointer. So
|
and the non-data variant is represented as the null pointer. So
|
||||||
`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
|
`Option<extern "C" fn(c_int) -> c_int>` is how one represents a nullable
|
||||||
function pointer using the C ABI.
|
function pointer using the C ABI.
|
||||||
|
|
||||||
|
# Calling Rust code from C
|
||||||
|
|
||||||
|
You may wish to compile Rust code in a way so that it can be called from C. This is
|
||||||
|
fairly easy, but requires a few things:
|
||||||
|
|
||||||
|
```
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn hello_rust() -> *const u8 {
|
||||||
|
"Hello, world!\0".as_ptr()
|
||||||
|
}
|
||||||
|
# fn main() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `extern` makes this function adhere to the C calling convention, as
|
||||||
|
discussed above in "[Foreign Calling
|
||||||
|
Conventions](guide-ffi.html#foreign-calling-conventions)". The `no_mangle`
|
||||||
|
attribute turns off Rust's name mangling, so that it is easier to link to.
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ fn foo(x: i32) -> i32 {
|
|||||||
```
|
```
|
||||||
|
|
||||||
The previous definition without `return` may look a bit strange if you haven't
|
The previous definition without `return` may look a bit strange if you haven't
|
||||||
worked in an expression-based language before, but it becomes intutive over
|
worked in an expression-based language before, but it becomes intuitive over
|
||||||
time. If this were production code, we wouldn't write it in that way anyway,
|
time. If this were production code, we wouldn't write it in that way anyway,
|
||||||
we'd write this:
|
we'd write this:
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ multiple types of arguments. For example, remember our `OptionalInt` type?
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
enum OptionalInt {
|
enum OptionalInt {
|
||||||
Value(int),
|
Value(i32),
|
||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -40,26 +40,26 @@ we substitute that type for the same type used in the generic. Here's an
|
|||||||
example of using `Option<T>`, with some extra type annotations:
|
example of using `Option<T>`, with some extra type annotations:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x: Option<int> = Some(5i);
|
let x: Option<i32> = Some(5);
|
||||||
```
|
```
|
||||||
|
|
||||||
In the type declaration, we say `Option<int>`. Note how similar this looks to
|
In the type declaration, we say `Option<i32>`. Note how similar this looks to
|
||||||
`Option<T>`. So, in this particular `Option`, `T` has the value of `int`. On
|
`Option<T>`. So, in this particular `Option`, `T` has the value of `i32`. On
|
||||||
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5i`.
|
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`.
|
||||||
Since that's an `int`, the two sides match, and Rust is happy. If they didn't
|
Since that's an `i32`, the two sides match, and Rust is happy. If they didn't
|
||||||
match, we'd get an error:
|
match, we'd get an error:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let x: Option<f64> = Some(5i);
|
let x: Option<f64> = Some(5);
|
||||||
// error: mismatched types: expected `core::option::Option<f64>`
|
// error: mismatched types: expected `core::option::Option<f64>`,
|
||||||
// but found `core::option::Option<int>` (expected f64 but found int)
|
// found `core::option::Option<_>` (expected f64 but found integral variable)
|
||||||
```
|
```
|
||||||
|
|
||||||
That doesn't mean we can't make `Option<T>`s that hold an `f64`! They just have to
|
That doesn't mean we can't make `Option<T>`s that hold an `f64`! They just have to
|
||||||
match up:
|
match up:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x: Option<int> = Some(5i);
|
let x: Option<i32> = Some(5);
|
||||||
let y: Option<f64> = Some(5.0f64);
|
let y: Option<f64> = Some(5.0f64);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -297,9 +297,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", input);
|
println!("You guessed: {}", input);
|
||||||
|
|
||||||
match cmp(input, secret_number) {
|
match cmp(input, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,9 +352,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", input);
|
println!("You guessed: {}", input);
|
||||||
|
|
||||||
match cmp(input, secret_number) {
|
match cmp(input, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,8 +422,8 @@ In this case, we say `x` is a `u32` explicitly, so Rust is able to properly
|
|||||||
tell `random()` what to generate. In a similar fashion, both of these work:
|
tell `random()` what to generate. In a similar fashion, both of these work:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let input_num = "5".parse::<u32>(); // input_num: Option<u32>
|
let input_num = "5".parse::<u32>(); // input_num: Option<u32>
|
||||||
let input_num: Option<u32> = "5".parse(); // input_num: Option<u32>
|
let input_num: Option<u32> = "5".parse(); // input_num: Option<u32>
|
||||||
```
|
```
|
||||||
|
|
||||||
Anyway, with us now converting our input to a number, our code looks like this:
|
Anyway, with us now converting our input to a number, our code looks like this:
|
||||||
@ -450,9 +450,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", input_num);
|
println!("You guessed: {}", input_num);
|
||||||
|
|
||||||
match cmp(input_num, secret_number) {
|
match cmp(input_num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +499,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -509,9 +509,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,7 +566,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -576,9 +576,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,7 +642,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -652,9 +652,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => println!("You win!"),
|
Ordering::Equal => println!("You win!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -718,7 +718,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -728,9 +728,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
println!("You win!");
|
println!("You win!");
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
@ -774,7 +774,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -784,9 +784,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
println!("You win!");
|
println!("You win!");
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
@ -851,7 +851,7 @@ fn main() {
|
|||||||
|
|
||||||
let num = match input_num {
|
let num = match input_num {
|
||||||
Some(num) => num,
|
Some(num) => num,
|
||||||
None => {
|
None => {
|
||||||
println!("Please input a number!");
|
println!("Please input a number!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -861,9 +861,9 @@ fn main() {
|
|||||||
println!("You guessed: {}", num);
|
println!("You guessed: {}", num);
|
||||||
|
|
||||||
match cmp(num, secret_number) {
|
match cmp(num, secret_number) {
|
||||||
Ordering::Less => println!("Too small!"),
|
Ordering::Less => println!("Too small!"),
|
||||||
Ordering::Greater => println!("Too big!"),
|
Ordering::Greater => println!("Too big!"),
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
println!("You win!");
|
println!("You win!");
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@ Let's talk about loops.
|
|||||||
Remember Rust's `for` loop? Here's an example:
|
Remember Rust's `for` loop? Here's an example:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
for x in range(0i, 10i) {
|
for x in range(0, 10) {
|
||||||
println!("{}", x);
|
println!("{}", x);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -17,7 +17,7 @@ call the `.next()` method on repeatedly, and it gives us a sequence of things.
|
|||||||
Like this:
|
Like this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut range = range(0i, 10i);
|
let mut range = range(0, 10);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match range.next() {
|
match range.next() {
|
||||||
@ -32,8 +32,8 @@ loop {
|
|||||||
We make a mutable binding to the return value of `range`, which is our iterator.
|
We make a mutable binding to the return value of `range`, which is our iterator.
|
||||||
We then `loop`, with an inner `match`. This `match` is used on the result of
|
We then `loop`, with an inner `match`. This `match` is used on the result of
|
||||||
`range.next()`, which gives us a reference to the next value of the iterator.
|
`range.next()`, which gives us a reference to the next value of the iterator.
|
||||||
`next` returns an `Option<int>`, in this case, which will be `Some(int)` when
|
`next` returns an `Option<i32>`, in this case, which will be `Some(i32)` when
|
||||||
we have a value and `None` once we run out. If we get `Some(int)`, we print it
|
we have a value and `None` once we run out. If we get `Some(i32)`, we print it
|
||||||
out, and if we get `None`, we `break` out of the loop.
|
out, and if we get `None`, we `break` out of the loop.
|
||||||
|
|
||||||
This code sample is basically the same as our `for` loop version. The `for`
|
This code sample is basically the same as our `for` loop version. The `for`
|
||||||
@ -50,9 +50,9 @@ primitive. For example, if you needed to iterate over the contents of
|
|||||||
a vector, you may be tempted to write this:
|
a vector, you may be tempted to write this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = vec![1i, 2i, 3i];
|
let nums = vec![1, 2, 3];
|
||||||
|
|
||||||
for i in range(0u, nums.len()) {
|
for i in range(0, nums.len()) {
|
||||||
println!("{}", nums[i]);
|
println!("{}", nums[i]);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -62,7 +62,7 @@ vectors returns an iterator which iterates through a reference to each element
|
|||||||
of the vector in turn. So write this:
|
of the vector in turn. So write this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = vec![1i, 2i, 3i];
|
let nums = vec![1, 2, 3];
|
||||||
|
|
||||||
for num in nums.iter() {
|
for num in nums.iter() {
|
||||||
println!("{}", num);
|
println!("{}", num);
|
||||||
@ -79,12 +79,12 @@ very common with iterators: we can ignore unnecessary bounds checks, but still
|
|||||||
know that we're safe.
|
know that we're safe.
|
||||||
|
|
||||||
There's another detail here that's not 100% clear because of how `println!`
|
There's another detail here that's not 100% clear because of how `println!`
|
||||||
works. `num` is actually of type `&int`. That is, it's a reference to an `int`,
|
works. `num` is actually of type `&i32`. That is, it's a reference to an `i32`,
|
||||||
not an `int` itself. `println!` handles the dereferencing for us, so we don't
|
not an `i32` itself. `println!` handles the dereferencing for us, so we don't
|
||||||
see it. This code works fine too:
|
see it. This code works fine too:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = vec![1i, 2i, 3i];
|
let nums = vec![1, 2, 3];
|
||||||
|
|
||||||
for num in nums.iter() {
|
for num in nums.iter() {
|
||||||
println!("{}", *num);
|
println!("{}", *num);
|
||||||
@ -118,7 +118,7 @@ The most common consumer is `collect()`. This code doesn't quite compile,
|
|||||||
but it shows the intention:
|
but it shows the intention:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let one_to_one_hundred = range(1i, 101i).collect();
|
let one_to_one_hundred = range(1, 101).collect();
|
||||||
```
|
```
|
||||||
|
|
||||||
As you can see, we call `collect()` on our iterator. `collect()` takes
|
As you can see, we call `collect()` on our iterator. `collect()` takes
|
||||||
@ -128,7 +128,7 @@ type of things you want to collect, and so you need to let it know.
|
|||||||
Here's the version that does compile:
|
Here's the version that does compile:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let one_to_one_hundred = range(1i, 101i).collect::<Vec<int>>();
|
let one_to_one_hundred = range(1, 101).collect::<Vec<i32>>();
|
||||||
```
|
```
|
||||||
|
|
||||||
If you remember, the `::<>` syntax allows us to give a type hint,
|
If you remember, the `::<>` syntax allows us to give a type hint,
|
||||||
@ -138,12 +138,12 @@ and so we tell it that we want a vector of integers.
|
|||||||
is one:
|
is one:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let greater_than_forty_two = range(0i, 100i)
|
let greater_than_forty_two = range(0, 100)
|
||||||
.find(|x| *x > 42);
|
.find(|x| *x > 42);
|
||||||
|
|
||||||
match greater_than_forty_two {
|
match greater_than_forty_two {
|
||||||
Some(_) => println!("We got some numbers!"),
|
Some(_) => println!("We got some numbers!"),
|
||||||
None => println!("No numbers found :("),
|
None => println!("No numbers found :("),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -155,8 +155,8 @@ element, `find` returns an `Option` rather than the element itself.
|
|||||||
Another important consumer is `fold`. Here's what it looks like:
|
Another important consumer is `fold`. Here's what it looks like:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let sum = range(1i, 4i)
|
let sum = range(1, 4)
|
||||||
.fold(0i, |sum, x| sum + x);
|
.fold(0, |sum, x| sum + x);
|
||||||
```
|
```
|
||||||
|
|
||||||
`fold()` is a consumer that looks like this:
|
`fold()` is a consumer that looks like this:
|
||||||
@ -172,24 +172,24 @@ in this iterator:
|
|||||||
|
|
||||||
| base | accumulator | element | closure result |
|
| base | accumulator | element | closure result |
|
||||||
|------|-------------|---------|----------------|
|
|------|-------------|---------|----------------|
|
||||||
| 0i | 0i | 1i | 1i |
|
| 0 | 0 | 1 | 1 |
|
||||||
| 0i | 1i | 2i | 3i |
|
| 0 | 1 | 2 | 3 |
|
||||||
| 0i | 3i | 3i | 6i |
|
| 0 | 3 | 3 | 6 |
|
||||||
|
|
||||||
We called `fold()` with these arguments:
|
We called `fold()` with these arguments:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
# range(1i, 4i)
|
# range(1, 4)
|
||||||
.fold(0i, |sum, x| sum + x);
|
.fold(0, |sum, x| sum + x);
|
||||||
```
|
```
|
||||||
|
|
||||||
So, `0i` is our base, `sum` is our accumulator, and `x` is our element. On the
|
So, `0` is our base, `sum` is our accumulator, and `x` is our element. On the
|
||||||
first iteration, we set `sum` to `0i`, and `x` is the first element of `nums`,
|
first iteration, we set `sum` to `0`, and `x` is the first element of `nums`,
|
||||||
`1i`. We then add `sum` and `x`, which gives us `0i + 1i = 1i`. On the second
|
`1`. We then add `sum` and `x`, which gives us `0 + 1 = 1`. On the second
|
||||||
iteration, that value becomes our accumulator, `sum`, and the element is
|
iteration, that value becomes our accumulator, `sum`, and the element is
|
||||||
the second element of the array, `2i`. `1i + 2i = 3i`, and so that becomes
|
the second element of the array, `2`. `1 + 2 = 3`, and so that becomes
|
||||||
the value of the accumulator for the last iteration. On that iteration,
|
the value of the accumulator for the last iteration. On that iteration,
|
||||||
`x` is the last element, `3i`, and `3i + 3i = 6i`, which is our final
|
`x` is the last element, `3`, and `3 + 3 = 6`, which is our final
|
||||||
result for our sum. `1 + 2 + 3 = 6`, and that's the result we got.
|
result for our sum. `1 + 2 + 3 = 6`, and that's the result we got.
|
||||||
|
|
||||||
Whew. `fold` can be a bit strange the first few times you see it, but once it
|
Whew. `fold` can be a bit strange the first few times you see it, but once it
|
||||||
@ -210,14 +210,14 @@ This code, for example, does not actually generate the numbers
|
|||||||
`1-100`, and just creates a value that represents the sequence:
|
`1-100`, and just creates a value that represents the sequence:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = range(1i, 100i);
|
let nums = range(1, 100);
|
||||||
```
|
```
|
||||||
|
|
||||||
Since we didn't do anything with the range, it didn't generate the sequence.
|
Since we didn't do anything with the range, it didn't generate the sequence.
|
||||||
Let's add the consumer:
|
Let's add the consumer:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = range(1i, 100i).collect::<Vec<int>>();
|
let nums = range(1, 100).collect::<Vec<i32>>();
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, `collect()` will require that `range()` give it some numbers, and so
|
Now, `collect()` will require that `range()` give it some numbers, and so
|
||||||
@ -228,7 +228,7 @@ which you've used before. `iter()` can turn a vector into a simple iterator
|
|||||||
that gives you each element in turn:
|
that gives you each element in turn:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let nums = [1i, 2i, 3i];
|
let nums = [1, 2, 3];
|
||||||
|
|
||||||
for num in nums.iter() {
|
for num in nums.iter() {
|
||||||
println!("{}", num);
|
println!("{}", num);
|
||||||
@ -239,12 +239,12 @@ These two basic iterators should serve you well. There are some more
|
|||||||
advanced iterators, including ones that are infinite. Like `count`:
|
advanced iterators, including ones that are infinite. Like `count`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
std::iter::count(1i, 5i);
|
std::iter::count(1, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
This iterator counts up from one, adding five each time. It will give
|
This iterator counts up from one, adding five each time. It will give
|
||||||
you a new integer every time, forever (well, technically, until it reaches the
|
you a new integer every time, forever (well, technically, until it reaches the
|
||||||
maximum number representable by an `int`). But since iterators are lazy,
|
maximum number representable by an `i32`). But since iterators are lazy,
|
||||||
that's okay! You probably don't want to use `collect()` on it, though...
|
that's okay! You probably don't want to use `collect()` on it, though...
|
||||||
|
|
||||||
That's enough about iterators. Iterator adapters are the last concept
|
That's enough about iterators. Iterator adapters are the last concept
|
||||||
@ -256,7 +256,7 @@ we need to talk about with regards to iterators. Let's get to it!
|
|||||||
a new iterator. The simplest one is called `map`:
|
a new iterator. The simplest one is called `map`:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
range(1i, 100i).map(|x| x + 1i);
|
range(1, 100).map(|x| x + 1);
|
||||||
```
|
```
|
||||||
|
|
||||||
`map` is called upon another iterator, and produces a new iterator where each
|
`map` is called upon another iterator, and produces a new iterator where each
|
||||||
@ -267,7 +267,7 @@ compile the example, you'll get a warning:
|
|||||||
```{notrust,ignore}
|
```{notrust,ignore}
|
||||||
warning: unused result which must be used: iterator adaptors are lazy and
|
warning: unused result which must be used: iterator adaptors are lazy and
|
||||||
do nothing unless consumed, #[warn(unused_must_use)] on by default
|
do nothing unless consumed, #[warn(unused_must_use)] on by default
|
||||||
range(1i, 100i).map(|x| x + 1i);
|
range(1, 100).map(|x| x + 1);
|
||||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ Laziness strikes again! That closure will never execute. This example
|
|||||||
doesn't print any numbers:
|
doesn't print any numbers:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
range(1i, 100i).map(|x| println!("{}", x));
|
range(1, 100).map(|x| println!("{}", x));
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are trying to execute a closure on an iterator for its side effects,
|
If you are trying to execute a closure on an iterator for its side effects,
|
||||||
@ -287,7 +287,7 @@ has no side effect on the original iterator. Let's try it out with our infinite
|
|||||||
iterator from before, `count()`:
|
iterator from before, `count()`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
for i in std::iter::count(1i, 5i).take(5) {
|
for i in std::iter::count(1, 5).take(5) {
|
||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -307,7 +307,7 @@ returns `true` or `false`. The new iterator `filter()` produces
|
|||||||
only the elements that that closure returns `true` for:
|
only the elements that that closure returns `true` for:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
for i in range(1i, 100i).filter(|&x| x % 2 == 0) {
|
for i in range(1, 100).filter(|&x| x % 2 == 0) {
|
||||||
println!("{}", i);
|
println!("{}", i);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -322,11 +322,11 @@ You can chain all three things together: start with an iterator, adapt it
|
|||||||
a few times, and then consume the result. Check it out:
|
a few times, and then consume the result. Check it out:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
range(1i, 1000i)
|
range(1, 1000)
|
||||||
.filter(|&x| x % 2 == 0)
|
.filter(|&x| x % 2 == 0)
|
||||||
.filter(|&x| x % 3 == 0)
|
.filter(|&x| x % 3 == 0)
|
||||||
.take(5)
|
.take(5)
|
||||||
.collect::<Vec<int>>();
|
.collect::<Vec<i32>>();
|
||||||
```
|
```
|
||||||
|
|
||||||
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
|
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
|
||||||
|
@ -54,7 +54,7 @@ The other kind of looping construct in Rust is the `while` loop. It looks like
|
|||||||
this:
|
this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut x = 5u32; // mut x: u32
|
let mut x = 5; // mut x: u32
|
||||||
let mut done = false; // mut done: bool
|
let mut done = false; // mut done: bool
|
||||||
|
|
||||||
while !done {
|
while !done {
|
||||||
@ -91,7 +91,7 @@ can do with safety and code generation, so you should always prefer
|
|||||||
Let's take a look at that `while` loop we had earlier:
|
Let's take a look at that `while` loop we had earlier:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut x = 5u32;
|
let mut x = 5;
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
|
|
||||||
while !done {
|
while !done {
|
||||||
@ -108,7 +108,7 @@ modifying iteration: `break` and `continue`.
|
|||||||
In this case, we can write the loop in a better way with `break`:
|
In this case, we can write the loop in a better way with `break`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut x = 5u32;
|
let mut x = 5;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
x += x - 3;
|
x += x - 3;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Macros Guide
|
% Macros
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@ -11,8 +11,8 @@ which both pattern-match on their input and both return early in one case,
|
|||||||
doing nothing otherwise:
|
doing nothing otherwise:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# enum T { SpecialA(uint), SpecialB(uint) }
|
# enum T { SpecialA(u32), SpecialB(u32) }
|
||||||
# fn f() -> uint {
|
# fn f() -> u32 {
|
||||||
# let input_1 = T::SpecialA(0);
|
# let input_1 = T::SpecialA(0);
|
||||||
# let input_2 = T::SpecialA(0);
|
# let input_2 = T::SpecialA(0);
|
||||||
match input_1 {
|
match input_1 {
|
||||||
@ -24,7 +24,7 @@ match input_2 {
|
|||||||
T::SpecialB(x) => { return x; }
|
T::SpecialB(x) => { return x; }
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
# return 0u;
|
# return 0;
|
||||||
# }
|
# }
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ lightweight custom syntax extensions, themselves defined using the
|
|||||||
the pattern in the above code:
|
the pattern in the above code:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# enum T { SpecialA(uint), SpecialB(uint) }
|
# enum T { SpecialA(u32), SpecialB(u32) }
|
||||||
# fn f() -> uint {
|
# fn f() -> u32 {
|
||||||
# let input_1 = T::SpecialA(0);
|
# let input_1 = T::SpecialA(0);
|
||||||
# let input_2 = T::SpecialA(0);
|
# let input_2 = T::SpecialA(0);
|
||||||
macro_rules! early_return {
|
macro_rules! early_return {
|
||||||
@ -165,8 +165,8 @@ separator token (a comma-separated list could be written `$(...),*`), and `+`
|
|||||||
instead of `*` to mean "at least one".
|
instead of `*` to mean "at least one".
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
|
# enum T { SpecialA(u32), SpecialB(u32), SpecialC(u32), SpecialD(u32) }
|
||||||
# fn f() -> uint {
|
# fn f() -> u32 {
|
||||||
# let input_1 = T::SpecialA(0);
|
# let input_1 = T::SpecialA(0);
|
||||||
# let input_2 = T::SpecialA(0);
|
# let input_2 = T::SpecialA(0);
|
||||||
macro_rules! early_return {
|
macro_rules! early_return {
|
||||||
@ -226,10 +226,10 @@ solves the problem.
|
|||||||
Now consider code like the following:
|
Now consider code like the following:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, u32), Bad1}
|
||||||
# struct T2 { body: T3 }
|
# struct T2 { body: T3 }
|
||||||
# enum T3 { Good2(uint), Bad2}
|
# enum T3 { Good2(u32), Bad2}
|
||||||
# fn f(x: T1) -> uint {
|
# fn f(x: T1) -> u32 {
|
||||||
match x {
|
match x {
|
||||||
T1::Good1(g1, val) => {
|
T1::Good1(g1, val) => {
|
||||||
match g1.body {
|
match g1.body {
|
||||||
@ -273,10 +273,10 @@ macro_rules! biased_match {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, u32), Bad1}
|
||||||
# struct T2 { body: T3 }
|
# struct T2 { body: T3 }
|
||||||
# enum T3 { Good2(uint), Bad2}
|
# enum T3 { Good2(u32), Bad2}
|
||||||
# fn f(x: T1) -> uint {
|
# fn f(x: T1) -> u32 {
|
||||||
biased_match!((x) -> (T1::Good1(g1, val)) else { return 0 };
|
biased_match!((x) -> (T1::Good1(g1, val)) else { return 0 };
|
||||||
binds g1, val );
|
binds g1, val );
|
||||||
biased_match!((g1.body) -> (T3::Good2(result) )
|
biased_match!((g1.body) -> (T3::Good2(result) )
|
||||||
@ -383,10 +383,10 @@ macro_rules! biased_match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# enum T1 { Good1(T2, uint), Bad1}
|
# enum T1 { Good1(T2, u32), Bad1}
|
||||||
# struct T2 { body: T3 }
|
# struct T2 { body: T3 }
|
||||||
# enum T3 { Good2(uint), Bad2}
|
# enum T3 { Good2(u32), Bad2}
|
||||||
# fn f(x: T1) -> uint {
|
# fn f(x: T1) -> u32 {
|
||||||
biased_match!(
|
biased_match!(
|
||||||
(x) -> (T1::Good1(g1, val)) else { return 0 };
|
(x) -> (T1::Good1(g1, val)) else { return 0 };
|
||||||
(g1.body) -> (T3::Good2(result) ) else { panic!("Didn't get Good2") };
|
(g1.body) -> (T3::Good2(result) ) else { panic!("Didn't get Good2") };
|
||||||
@ -528,7 +528,7 @@ A further difficulty occurs when a macro is used in multiple crates. Say that
|
|||||||
`mylib` defines
|
`mylib` defines
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub fn increment(x: uint) -> uint {
|
pub fn increment(x: u32) -> u32 {
|
||||||
x + 1
|
x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +84,9 @@ fn main() {
|
|||||||
let y = 10;
|
let y = 10;
|
||||||
|
|
||||||
match cmp(x, y) {
|
match cmp(x, y) {
|
||||||
Ordering::Less => println!("less"),
|
Ordering::Less => println!("less"),
|
||||||
Ordering::Greater => println!("greater"),
|
Ordering::Greater => println!("greater"),
|
||||||
Ordering::Equal => println!("equal"),
|
Ordering::Equal => println!("equal"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -112,12 +112,12 @@ fn main() {
|
|||||||
|
|
||||||
match x {
|
match x {
|
||||||
OptionalInt::Value(n) => println!("x is {}", n),
|
OptionalInt::Value(n) => println!("x is {}", n),
|
||||||
OptionalInt::Missing => println!("x is missing!"),
|
OptionalInt::Missing => println!("x is missing!"),
|
||||||
}
|
}
|
||||||
|
|
||||||
match y {
|
match y {
|
||||||
OptionalInt::Value(n) => println!("y is {}", n),
|
OptionalInt::Value(n) => println!("y is {}", n),
|
||||||
OptionalInt::Missing => println!("y is missing!"),
|
OptionalInt::Missing => println!("y is missing!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -146,9 +146,9 @@ fn main() {
|
|||||||
let y = 10;
|
let y = 10;
|
||||||
|
|
||||||
println!("{}", match cmp(x, y) {
|
println!("{}", match cmp(x, y) {
|
||||||
Ordering::Less => "less",
|
Ordering::Less => "less",
|
||||||
Ordering::Greater => "greater",
|
Ordering::Greater => "greater",
|
||||||
Ordering::Equal => "equal",
|
Ordering::Equal => "equal",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Ownership Guide
|
% Ownership
|
||||||
|
|
||||||
This guide presents Rust's ownership system. This is one of Rust's most unique
|
This guide presents Rust's ownership system. This is one of Rust's most unique
|
||||||
and compelling features, with which Rust developers should become quite
|
and compelling features, with which Rust developers should become quite
|
||||||
@ -418,7 +418,7 @@ struct Wheel {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let car = Car { name: "DeLorean".to_string() };
|
let car = Car { name: "DeLorean".to_string() };
|
||||||
|
|
||||||
for _ in range(0u, 4) {
|
for _ in range(0, 4) {
|
||||||
Wheel { size: 360, owner: car };
|
Wheel { size: 360, owner: car };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +456,7 @@ fn main() {
|
|||||||
|
|
||||||
let car_owner = Rc::new(car);
|
let car_owner = Rc::new(car);
|
||||||
|
|
||||||
for _ in range(0u, 4) {
|
for _ in range(0, 4) {
|
||||||
Wheel { size: 360, owner: car_owner.clone() };
|
Wheel { size: 360, owner: car_owner.clone() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,31 +517,31 @@ Here are some examples of functions with elided lifetimes, and the version of
|
|||||||
what the elided lifetimes are expand to:
|
what the elided lifetimes are expand to:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
fn print(s: &str); // elided
|
fn print(s: &str); // elided
|
||||||
fn print<'a>(s: &'a str); // expanded
|
fn print<'a>(s: &'a str); // expanded
|
||||||
|
|
||||||
fn debug(lvl: u32, s: &str); // elided
|
fn debug(lvl: u32, s: &str); // elided
|
||||||
fn debug<'a>(lvl: u32, s: &'a str); // expanded
|
fn debug<'a>(lvl: u32, s: &'a str); // expanded
|
||||||
|
|
||||||
// In the preceeding example, `lvl` doesn't need a lifetime because it's not a
|
// In the preceeding example, `lvl` doesn't need a lifetime because it's not a
|
||||||
// reference (`&`). Only things relating to references (such as a `struct`
|
// reference (`&`). Only things relating to references (such as a `struct`
|
||||||
// which contains a reference) need lifetimes.
|
// which contains a reference) need lifetimes.
|
||||||
|
|
||||||
fn substr(s: &str, until: u32) -> &str; // elided
|
fn substr(s: &str, until: u32) -> &str; // elided
|
||||||
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
|
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded
|
||||||
|
|
||||||
fn get_str() -> &str; // ILLEGAL, no inputs
|
fn get_str() -> &str; // ILLEGAL, no inputs
|
||||||
|
|
||||||
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
|
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
|
||||||
|
|
||||||
fn get_mut(&mut self) -> &mut T; // elided
|
fn get_mut(&mut self) -> &mut T; // elided
|
||||||
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
|
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
|
||||||
|
|
||||||
fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
|
fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
|
||||||
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
|
fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
|
||||||
|
|
||||||
fn new(buf: &mut [u8]) -> BufWriter; // elided
|
fn new(buf: &mut [u8]) -> BufWriter; // elided
|
||||||
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
|
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
|
||||||
```
|
```
|
||||||
|
|
||||||
# Related Resources
|
# Related Resources
|
||||||
|
@ -8,7 +8,7 @@ A quick refresher: you can match against literals directly, and `_` acts as an
|
|||||||
*any* case:
|
*any* case:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 1i;
|
let x = 1;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
1 => println!("one"),
|
1 => println!("one"),
|
||||||
@ -21,7 +21,7 @@ match x {
|
|||||||
You can match multiple patterns with `|`:
|
You can match multiple patterns with `|`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 1i;
|
let x = 1;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
1 | 2 => println!("one or two"),
|
1 | 2 => println!("one or two"),
|
||||||
@ -33,7 +33,7 @@ match x {
|
|||||||
You can match a range of values with `...`:
|
You can match a range of values with `...`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 1i;
|
let x = 1;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
1 ... 5 => println!("one through five"),
|
1 ... 5 => println!("one through five"),
|
||||||
@ -47,7 +47,7 @@ If you're matching multiple things, via a `|` or a `...`, you can bind
|
|||||||
the value to a name with `@`:
|
the value to a name with `@`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 1i;
|
let x = 1;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
e @ 1 ... 5 => println!("got a range element {}", e),
|
e @ 1 ... 5 => println!("got a range element {}", e),
|
||||||
@ -60,15 +60,15 @@ ignore the value and type in the variant:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
enum OptionalInt {
|
enum OptionalInt {
|
||||||
Value(int),
|
Value(i32),
|
||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = OptionalInt::Value(5i);
|
let x = OptionalInt::Value(5);
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
OptionalInt::Value(..) => println!("Got an int!"),
|
OptionalInt::Value(..) => println!("Got an int!"),
|
||||||
OptionalInt::Missing => println!("No such luck."),
|
OptionalInt::Missing => println!("No such luck."),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -76,16 +76,16 @@ You can introduce *match guards* with `if`:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
enum OptionalInt {
|
enum OptionalInt {
|
||||||
Value(int),
|
Value(i32),
|
||||||
Missing,
|
Missing,
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = OptionalInt::Value(5i);
|
let x = OptionalInt::Value(5);
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
|
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
|
||||||
OptionalInt::Value(..) => println!("Got an int!"),
|
OptionalInt::Value(..) => println!("Got an int!"),
|
||||||
OptionalInt::Missing => println!("No such luck."),
|
OptionalInt::Missing => println!("No such luck."),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -93,33 +93,33 @@ If you're matching on a pointer, you can use the same syntax as you declared it
|
|||||||
with. First, `&`:
|
with. First, `&`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = &5i;
|
let x = &5;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
&val => println!("Got a value: {}", val),
|
&val => println!("Got a value: {}", val),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, the `val` inside the `match` has type `int`. In other words, the left-hand
|
Here, the `val` inside the `match` has type `i32`. In other words, the left-hand
|
||||||
side of the pattern destructures the value. If we have `&5i`, then in `&val`, `val`
|
side of the pattern destructures the value. If we have `&5`, then in `&val`, `val`
|
||||||
would be `5i`.
|
would be `5`.
|
||||||
|
|
||||||
If you want to get a reference, use the `ref` keyword:
|
If you want to get a reference, use the `ref` keyword:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
ref r => println!("Got a reference to {}", r),
|
ref r => println!("Got a reference to {}", r),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, the `r` inside the `match` has the type `&int`. In other words, the `ref`
|
Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
|
||||||
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
||||||
reference, `ref mut` will work in the same way:
|
reference, `ref mut` will work in the same way:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut x = 5i;
|
let mut x = 5;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
ref mut mr => println!("Got a mutable reference to {}", mr),
|
ref mut mr => println!("Got a mutable reference to {}", mr),
|
||||||
@ -131,11 +131,11 @@ If you have a struct, you can destructure it inside of a pattern:
|
|||||||
```{rust}
|
```{rust}
|
||||||
# #![allow(non_shorthand_field_patterns)]
|
# #![allow(non_shorthand_field_patterns)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: int,
|
x: i32,
|
||||||
y: int,
|
y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
let origin = Point { x: 0i, y: 0i };
|
let origin = Point { x: 0, y: 0 };
|
||||||
|
|
||||||
match origin {
|
match origin {
|
||||||
Point { x: x, y: y } => println!("({},{})", x, y),
|
Point { x: x, y: y } => println!("({},{})", x, y),
|
||||||
@ -147,11 +147,11 @@ If we only care about some of the values, we don't have to give them all names:
|
|||||||
```{rust}
|
```{rust}
|
||||||
# #![allow(non_shorthand_field_patterns)]
|
# #![allow(non_shorthand_field_patterns)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: int,
|
x: i32,
|
||||||
y: int,
|
y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
let origin = Point { x: 0i, y: 0i };
|
let origin = Point { x: 0, y: 0 };
|
||||||
|
|
||||||
match origin {
|
match origin {
|
||||||
Point { x: x, .. } => println!("x is {}", x),
|
Point { x: x, .. } => println!("x is {}", x),
|
||||||
@ -163,11 +163,11 @@ You can do this kind of match on any member, not just the first:
|
|||||||
```{rust}
|
```{rust}
|
||||||
# #![allow(non_shorthand_field_patterns)]
|
# #![allow(non_shorthand_field_patterns)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: int,
|
x: i32,
|
||||||
y: int,
|
y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
let origin = Point { x: 0i, y: 0i };
|
let origin = Point { x: 0, y: 0 };
|
||||||
|
|
||||||
match origin {
|
match origin {
|
||||||
Point { y: y, .. } => println!("y is {}", y),
|
Point { y: y, .. } => println!("y is {}", y),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Compiler Plugins Guide
|
% Compiler Plugins
|
||||||
|
|
||||||
<div class="unstable-feature">
|
<div class="unstable-feature">
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ use rustc::plugin::Registry;
|
|||||||
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||||
-> Box<MacResult + 'static> {
|
-> Box<MacResult + 'static> {
|
||||||
|
|
||||||
static NUMERALS: &'static [(&'static str, uint)] = &[
|
static NUMERALS: &'static [(&'static str, u32)] = &[
|
||||||
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
|
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
|
||||||
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
|
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
|
||||||
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
|
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
|
||||||
@ -83,7 +83,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut text = text.as_slice();
|
let mut text = text.as_slice();
|
||||||
let mut total = 0u;
|
let mut total = 0;
|
||||||
while !text.is_empty() {
|
while !text.is_empty() {
|
||||||
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
|
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
|
||||||
Some(&(rn, val)) => {
|
Some(&(rn, val)) => {
|
||||||
@ -118,7 +118,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The advantages over a simple `fn(&str) -> uint` are:
|
The advantages over a simple `fn(&str) -> u32` are:
|
||||||
|
|
||||||
* The (arbitrarily complex) conversion is done at compile time.
|
* The (arbitrarily complex) conversion is done at compile time.
|
||||||
* Input validation is also performed at compile time.
|
* Input validation is also performed at compile time.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Pointer Guide
|
% Pointers
|
||||||
|
|
||||||
Rust's pointers are one of its more unique and compelling features. Pointers
|
Rust's pointers are one of its more unique and compelling features. Pointers
|
||||||
are also one of the more confusing topics for newcomers to Rust. They can also
|
are also one of the more confusing topics for newcomers to Rust. They can also
|
||||||
@ -28,9 +28,10 @@ question](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-
|
|||||||
as the rest of this guide assumes you know the difference.) Like this:
|
as the rest of this guide assumes you know the difference.) Like this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = 8i;
|
let y = 8;
|
||||||
```
|
```
|
||||||
|
|
||||||
| location | value |
|
| location | value |
|
||||||
|----------|-------|
|
|----------|-------|
|
||||||
| 0xd3e030 | 5 |
|
| 0xd3e030 | 5 |
|
||||||
@ -46,10 +47,11 @@ Let's introduce a pointer. In some languages, there is just one type of
|
|||||||
*reference*, which is the simplest kind of pointer.
|
*reference*, which is the simplest kind of pointer.
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = 8i;
|
let y = 8;
|
||||||
let z = &y;
|
let z = &y;
|
||||||
```
|
```
|
||||||
|
|
||||||
|location | value |
|
|location | value |
|
||||||
|-------- |----------|
|
|-------- |----------|
|
||||||
|0xd3e030 | 5 |
|
|0xd3e030 | 5 |
|
||||||
@ -58,12 +60,12 @@ let z = &y;
|
|||||||
|
|
||||||
See the difference? Rather than contain a value, the value of a pointer is a
|
See the difference? Rather than contain a value, the value of a pointer is a
|
||||||
location in memory. In this case, the location of `y`. `x` and `y` have the
|
location in memory. In this case, the location of `y`. `x` and `y` have the
|
||||||
type `int`, but `z` has the type `&int`. We can print this location using the
|
type `i32`, but `z` has the type `&i32`. We can print this location using the
|
||||||
`{:p}` format string:
|
`{:p}` format string:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = 8i;
|
let y = 8;
|
||||||
let z = &y;
|
let z = &y;
|
||||||
|
|
||||||
println!("{:p}", z);
|
println!("{:p}", z);
|
||||||
@ -71,12 +73,12 @@ println!("{:p}", z);
|
|||||||
|
|
||||||
This would print `0xd3e028`, with our fictional memory addresses.
|
This would print `0xd3e028`, with our fictional memory addresses.
|
||||||
|
|
||||||
Because `int` and `&int` are different types, we can't, for example, add them
|
Because `i32` and `&i32` are different types, we can't, for example, add them
|
||||||
together:
|
together:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = 8i;
|
let y = 8;
|
||||||
let z = &y;
|
let z = &y;
|
||||||
|
|
||||||
println!("{}", x + z);
|
println!("{}", x + z);
|
||||||
@ -85,7 +87,7 @@ println!("{}", x + z);
|
|||||||
This gives us an error:
|
This gives us an error:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
hello.rs:6:24: 6:25 error: mismatched types: expected `int` but found `&int` (expected int but found &-ptr)
|
hello.rs:6:24: 6:25 error: mismatched types: expected `i32` but found `&i32` (expected i32 but found &-ptr)
|
||||||
hello.rs:6 println!("{}", x + z);
|
hello.rs:6 println!("{}", x + z);
|
||||||
^
|
^
|
||||||
```
|
```
|
||||||
@ -95,8 +97,8 @@ pointer means accessing the value at the location stored in the pointer. This
|
|||||||
will work:
|
will work:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = 8i;
|
let y = 8;
|
||||||
let z = &y;
|
let z = &y;
|
||||||
|
|
||||||
println!("{}", x + *z);
|
println!("{}", x + *z);
|
||||||
@ -153,7 +155,7 @@ So what do pointers have to do with this? Well, since pointers point to a
|
|||||||
location in memory...
|
location in memory...
|
||||||
|
|
||||||
```text
|
```text
|
||||||
func foo(&int x) {
|
func foo(&i32 x) {
|
||||||
*x = 5
|
*x = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +254,7 @@ The most basic type of pointer that Rust has is called a *reference*. Rust
|
|||||||
references look like this:
|
references look like this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = &x;
|
let y = &x;
|
||||||
|
|
||||||
println!("{}", *y);
|
println!("{}", *y);
|
||||||
@ -269,18 +271,18 @@ referent, because `println!` will automatically dereference it for us.
|
|||||||
Here's a function that takes a reference:
|
Here's a function that takes a reference:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: &int) -> int { *x + 1 }
|
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use `&` as an operator to create a reference, so we can
|
You can also use `&` as an operator to create a reference, so we can
|
||||||
call this function in two different ways:
|
call this function in two different ways:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: &int) -> int { *x + 1 }
|
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = &x;
|
let y = &x;
|
||||||
|
|
||||||
println!("{}", succ(y));
|
println!("{}", succ(y));
|
||||||
@ -294,13 +296,13 @@ Of course, if this were real code, we wouldn't bother with the reference, and
|
|||||||
just write:
|
just write:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: int) -> int { x + 1 }
|
fn succ(x: i32) -> i32 { x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
References are immutable by default:
|
References are immutable by default:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = &x;
|
let y = &x;
|
||||||
|
|
||||||
*y = 5; // error: cannot assign to immutable dereference of `&`-pointer `*y`
|
*y = 5; // error: cannot assign to immutable dereference of `&`-pointer `*y`
|
||||||
@ -310,21 +312,21 @@ They can be made mutable with `mut`, but only if its referent is also mutable.
|
|||||||
This works:
|
This works:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let mut x = 5i;
|
let mut x = 5;
|
||||||
let y = &mut x;
|
let y = &mut x;
|
||||||
```
|
```
|
||||||
|
|
||||||
This does not:
|
This does not:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable
|
let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable
|
||||||
```
|
```
|
||||||
|
|
||||||
Immutable pointers are allowed to alias:
|
Immutable pointers are allowed to alias:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = 5i;
|
let x = 5;
|
||||||
let y = &x;
|
let y = &x;
|
||||||
let z = &x;
|
let z = &x;
|
||||||
```
|
```
|
||||||
@ -332,7 +334,7 @@ let z = &x;
|
|||||||
Mutable ones, however, are not:
|
Mutable ones, however, are not:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
let mut x = 5i;
|
let mut x = 5;
|
||||||
let y = &mut x;
|
let y = &mut x;
|
||||||
let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time
|
let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time
|
||||||
```
|
```
|
||||||
@ -359,7 +361,7 @@ duration a *lifetime*. Let's try a more complex example:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = &mut 5i;
|
let x = &mut 5;
|
||||||
|
|
||||||
if *x < 10 {
|
if *x < 10 {
|
||||||
let y = &x;
|
let y = &x;
|
||||||
@ -380,7 +382,7 @@ mutated, and therefore, lets us pass. This wouldn't work:
|
|||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = &mut 5i;
|
let x = &mut 5;
|
||||||
|
|
||||||
if *x < 10 {
|
if *x < 10 {
|
||||||
let y = &x;
|
let y = &x;
|
||||||
@ -425,13 +427,13 @@ References just borrow ownership, which is more polite if you don't need the
|
|||||||
ownership. In other words, prefer:
|
ownership. In other words, prefer:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: &int) -> int { *x + 1 }
|
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
to
|
to
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: Box<int>) -> int { *x + 1 }
|
fn succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
As a corollary to that rule, references allow you to accept a wide variety of
|
As a corollary to that rule, references allow you to accept a wide variety of
|
||||||
@ -439,7 +441,7 @@ other pointers, and so are useful so that you don't have to write a number
|
|||||||
of variants per pointer. In other words, prefer:
|
of variants per pointer. In other words, prefer:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn succ(x: &int) -> int { *x + 1 }
|
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
to
|
to
|
||||||
@ -447,9 +449,9 @@ to
|
|||||||
```{rust}
|
```{rust}
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn box_succ(x: Box<int>) -> int { *x + 1 }
|
fn box_succ(x: Box<i32>) -> i32 { *x + 1 }
|
||||||
|
|
||||||
fn rc_succ(x: Rc<int>) -> int { *x + 1 }
|
fn rc_succ(x: Rc<i32>) -> i32 { *x + 1 }
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the caller of your function will have to modify their calls slightly:
|
Note that the caller of your function will have to modify their calls slightly:
|
||||||
@ -457,11 +459,11 @@ Note that the caller of your function will have to modify their calls slightly:
|
|||||||
```{rust}
|
```{rust}
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn succ(x: &int) -> int { *x + 1 }
|
fn succ(x: &i32) -> i32 { *x + 1 }
|
||||||
|
|
||||||
let ref_x = &5i;
|
let ref_x = &5;
|
||||||
let box_x = Box::new(5i);
|
let box_x = Box::new(5);
|
||||||
let rc_x = Rc::new(5i);
|
let rc_x = Rc::new(5);
|
||||||
|
|
||||||
succ(ref_x);
|
succ(ref_x);
|
||||||
succ(&*box_x);
|
succ(&*box_x);
|
||||||
@ -477,7 +479,7 @@ those contents.
|
|||||||
heap allocation in Rust. Creating a box looks like this:
|
heap allocation in Rust. Creating a box looks like this:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
```
|
```
|
||||||
|
|
||||||
Boxes are heap allocated and they are deallocated automatically by Rust when
|
Boxes are heap allocated and they are deallocated automatically by Rust when
|
||||||
@ -485,7 +487,7 @@ they go out of scope:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
{
|
{
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
|
|
||||||
// stuff happens
|
// stuff happens
|
||||||
|
|
||||||
@ -505,7 +507,7 @@ boxes, though. As a rough approximation, you can treat this Rust code:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
{
|
{
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
|
|
||||||
// stuff happens
|
// stuff happens
|
||||||
}
|
}
|
||||||
@ -544,12 +546,12 @@ for more detail on how lifetimes work.
|
|||||||
Using boxes and references together is very common. For example:
|
Using boxes and references together is very common. For example:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn add_one(x: &int) -> int {
|
fn add_one(x: &i32) -> i32 {
|
||||||
*x + 1
|
*x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
|
|
||||||
println!("{}", add_one(&*x));
|
println!("{}", add_one(&*x));
|
||||||
}
|
}
|
||||||
@ -561,12 +563,12 @@ function, and since it's only reading the value, allows it.
|
|||||||
We can borrow `x` multiple times, as long as it's not simultaneous:
|
We can borrow `x` multiple times, as long as it's not simultaneous:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
fn add_one(x: &int) -> int {
|
fn add_one(x: &i32) -> i32 {
|
||||||
*x + 1
|
*x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
|
|
||||||
println!("{}", add_one(&*x));
|
println!("{}", add_one(&*x));
|
||||||
println!("{}", add_one(&*x));
|
println!("{}", add_one(&*x));
|
||||||
@ -577,12 +579,12 @@ fn main() {
|
|||||||
Or as long as it's not a mutable borrow. This will error:
|
Or as long as it's not a mutable borrow. This will error:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
fn add_one(x: &mut int) -> int {
|
fn add_one(x: &mut i32) -> i32 {
|
||||||
*x + 1
|
*x + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = Box::new(5i);
|
let x = Box::new(5);
|
||||||
|
|
||||||
println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference
|
println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference
|
||||||
// of `&`-pointer as mutable
|
// of `&`-pointer as mutable
|
||||||
@ -610,7 +612,7 @@ enum List<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let list: List<int> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))));
|
let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil))))));
|
||||||
println!("{:?}", list);
|
println!("{:?}", list);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -659,10 +661,10 @@ so as to avoid copying a large data structure. For example:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
struct BigStruct {
|
struct BigStruct {
|
||||||
one: int,
|
one: i32,
|
||||||
two: int,
|
two: i32,
|
||||||
// etc
|
// etc
|
||||||
one_hundred: int,
|
one_hundred: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
||||||
@ -687,10 +689,10 @@ This is an antipattern in Rust. Instead, write this:
|
|||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
struct BigStruct {
|
struct BigStruct {
|
||||||
one: int,
|
one: i32,
|
||||||
two: int,
|
two: i32,
|
||||||
// etc
|
// etc
|
||||||
one_hundred: int,
|
one_hundred: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: Box<BigStruct>) -> BigStruct {
|
fn foo(x: Box<BigStruct>) -> BigStruct {
|
||||||
|
@ -83,12 +83,12 @@ fn main() {
|
|||||||
|
|
||||||
match x {
|
match x {
|
||||||
OptionalInt::Value(n) => println!("x is {}", n),
|
OptionalInt::Value(n) => println!("x is {}", n),
|
||||||
OptionalInt::Missing => println!("x is missing!"),
|
OptionalInt::Missing => println!("x is missing!"),
|
||||||
}
|
}
|
||||||
|
|
||||||
match y {
|
match y {
|
||||||
OptionalInt::Value(n) => println!("y is {}", n),
|
OptionalInt::Value(n) => println!("y is {}", n),
|
||||||
OptionalInt::Missing => println!("y is missing!"),
|
OptionalInt::Missing => println!("y is missing!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -141,11 +141,11 @@ use std::io;
|
|||||||
fn main() {
|
fn main() {
|
||||||
println!("Type something!");
|
println!("Type something!");
|
||||||
|
|
||||||
// here, we'll show the types at each step
|
// here, we'll show the types at each step
|
||||||
|
|
||||||
let input = io::stdin() // std::io::stdio::StdinReader
|
let input = io::stdin() // std::io::stdio::StdinReader
|
||||||
.read_line() // IoResult<String>
|
.read_line() // IoResult<String>
|
||||||
.ok() // Option<String>
|
.ok() // Option<String>
|
||||||
.expect("Failed to read line"); // String
|
.expect("Failed to read line"); // String
|
||||||
|
|
||||||
println!("{}", input);
|
println!("{}", input);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% The Rust Testing Guide
|
% Testing
|
||||||
|
|
||||||
> Program testing can be a very effective way to show the presence of bugs, but
|
> Program testing can be a very effective way to show the presence of bugs, but
|
||||||
> it is hopelessly inadequate for showing their absence.
|
> it is hopelessly inadequate for showing their absence.
|
||||||
@ -512,7 +512,7 @@ use test::Bencher;
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn bench_xor_1000_ints(b: &mut Bencher) {
|
fn bench_xor_1000_ints(b: &mut Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
range(0u, 1000).fold(0, |old, new| old ^ new);
|
range(0, 1000).fold(0, |old, new| old ^ new);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -537,7 +537,7 @@ computation entirely. This could be done for the example above by adjusting the
|
|||||||
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
|
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
// note lack of `;` (could also use an explicit `return`).
|
// note lack of `;` (could also use an explicit `return`).
|
||||||
range(0u, 1000).fold(0, |old, new| old ^ new)
|
range(0, 1000).fold(0, |old, new| old ^ new)
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -51,13 +51,15 @@ closure is limited to capturing `Send`-able data from its environment
|
|||||||
ensures that `spawn` can safely move the entire closure and all its
|
ensures that `spawn` can safely move the entire closure and all its
|
||||||
associated state into an entirely different thread for execution.
|
associated state into an entirely different thread for execution.
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
# use std::thread::spawn;
|
use std::thread::Thread;
|
||||||
# fn generate_thread_number() -> int { 0 }
|
|
||||||
|
fn generate_thread_number() -> i32 { 4 } // a very simple generation
|
||||||
|
|
||||||
// Generate some state locally
|
// Generate some state locally
|
||||||
let child_thread_number = generate_thread_number();
|
let child_thread_number = generate_thread_number();
|
||||||
|
|
||||||
spawn(move || {
|
Thread::spawn(move || {
|
||||||
// Capture it in the remote thread. The `move` keyword indicates
|
// Capture it in the remote thread. The `move` keyword indicates
|
||||||
// that this closure should move `child_thread_number` into its
|
// that this closure should move `child_thread_number` into its
|
||||||
// environment, rather than capturing a reference into the
|
// environment, rather than capturing a reference into the
|
||||||
@ -77,20 +79,22 @@ The simplest way to create a channel is to use the `channel` function to create
|
|||||||
of a channel, and a *receiver* is the receiving endpoint. Consider the following
|
of a channel, and a *receiver* is the receiving endpoint. Consider the following
|
||||||
example of calculating two results concurrently:
|
example of calculating two results concurrently:
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
# use std::thread::spawn;
|
use std::thread::Thread;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
let (tx, rx): (mpsc::Sender<u32>, mpsc::Receiver<u32>) = mpsc::channel();
|
||||||
|
|
||||||
spawn(move || {
|
Thread::spawn(move || {
|
||||||
let result = some_expensive_computation();
|
let result = some_expensive_computation();
|
||||||
tx.send(result);
|
tx.send(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
some_other_expensive_computation();
|
some_other_expensive_computation();
|
||||||
let result = rx.recv();
|
let result = rx.recv();
|
||||||
# fn some_expensive_computation() -> int { 42 }
|
|
||||||
# fn some_other_expensive_computation() {}
|
fn some_expensive_computation() -> u32 { 42 } // very expensive ;)
|
||||||
|
fn some_other_expensive_computation() {} // even more so
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's examine this example in detail. First, the `let` statement creates a
|
Let's examine this example in detail. First, the `let` statement creates a
|
||||||
@ -98,19 +102,21 @@ stream for sending and receiving integers (the left-hand side of the `let`,
|
|||||||
`(tx, rx)`, is an example of a destructuring let: the pattern separates a tuple
|
`(tx, rx)`, is an example of a destructuring let: the pattern separates a tuple
|
||||||
into its component parts).
|
into its component parts).
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
# use std::sync::mpsc;
|
||||||
|
let (tx, rx): (mpsc::Sender<u32>, mpsc::Receiver<u32>) = mpsc::channel();
|
||||||
```
|
```
|
||||||
|
|
||||||
The child thread will use the sender to send data to the parent thread, which will
|
The child thread will use the sender to send data to the parent thread, which will
|
||||||
wait to receive the data on the receiver. The next statement spawns the child
|
wait to receive the data on the receiver. The next statement spawns the child
|
||||||
thread.
|
thread.
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
# use std::thread::spawn;
|
# use std::thread::Thread;
|
||||||
# fn some_expensive_computation() -> int { 42 }
|
# use std::sync::mpsc;
|
||||||
# let (tx, rx) = channel();
|
# fn some_expensive_computation() -> u32 { 42 }
|
||||||
spawn(move || {
|
# let (tx, rx) = mpsc::channel();
|
||||||
|
Thread::spawn(move || {
|
||||||
let result = some_expensive_computation();
|
let result = some_expensive_computation();
|
||||||
tx.send(result);
|
tx.send(result);
|
||||||
});
|
});
|
||||||
@ -125,9 +131,10 @@ computation, then sends the result over the captured channel.
|
|||||||
Finally, the parent continues with some other expensive computation, then waits
|
Finally, the parent continues with some other expensive computation, then waits
|
||||||
for the child's result to arrive on the receiver:
|
for the child's result to arrive on the receiver:
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
|
# use std::sync::mpsc;
|
||||||
# fn some_other_expensive_computation() {}
|
# fn some_other_expensive_computation() {}
|
||||||
# let (tx, rx) = channel::<int>();
|
# let (tx, rx) = mpsc::channel::<u32>();
|
||||||
# tx.send(0);
|
# tx.send(0);
|
||||||
some_other_expensive_computation();
|
some_other_expensive_computation();
|
||||||
let result = rx.recv();
|
let result = rx.recv();
|
||||||
@ -140,8 +147,9 @@ single `Receiver` value. What if our example needed to compute multiple
|
|||||||
results across a number of threads? The following program is ill-typed:
|
results across a number of threads? The following program is ill-typed:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
# fn some_expensive_computation() -> int { 42 }
|
# use std::sync::mpsc;
|
||||||
let (tx, rx) = channel();
|
# fn some_expensive_computation() -> u32 { 42 }
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
tx.send(some_expensive_computation());
|
tx.send(some_expensive_computation());
|
||||||
@ -156,19 +164,22 @@ spawn(move || {
|
|||||||
|
|
||||||
Instead we can clone the `tx`, which allows for multiple senders.
|
Instead we can clone the `tx`, which allows for multiple senders.
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
let (tx, rx) = channel();
|
use std::thread::Thread;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
for init_val in range(0u, 3) {
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
for init_val in 0 .. 3 {
|
||||||
// Create a new channel handle to distribute to the child thread
|
// Create a new channel handle to distribute to the child thread
|
||||||
let child_tx = tx.clone();
|
let child_tx = tx.clone();
|
||||||
spawn(move || {
|
Thread::spawn(move || {
|
||||||
child_tx.send(some_expensive_computation(init_val));
|
child_tx.send(some_expensive_computation(init_val));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = rx.recv() + rx.recv() + rx.recv();
|
let result = rx.recv().unwrap() + rx.recv().unwrap() + rx.recv().unwrap();
|
||||||
# fn some_expensive_computation(_i: uint) -> int { 42 }
|
# fn some_expensive_computation(_i: u32) -> u32 { 42 }
|
||||||
```
|
```
|
||||||
|
|
||||||
Cloning a `Sender` produces a new handle to the same channel, allowing multiple
|
Cloning a `Sender` produces a new handle to the same channel, allowing multiple
|
||||||
@ -181,21 +192,22 @@ Note that the above cloning example is somewhat contrived since you could also
|
|||||||
simply use three `Sender` pairs, but it serves to illustrate the point. For
|
simply use three `Sender` pairs, but it serves to illustrate the point. For
|
||||||
reference, written with multiple streams, it might look like the example below.
|
reference, written with multiple streams, it might look like the example below.
|
||||||
|
|
||||||
```{rust,ignore}
|
```rust
|
||||||
# use std::thread::spawn;
|
use std::thread::Thread;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
// Create a vector of ports, one for each child thread
|
// Create a vector of ports, one for each child thread
|
||||||
let rxs = Vec::from_fn(3, |init_val| {
|
let rxs = (0 .. 3).map(|&:init_val| {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
spawn(move || {
|
Thread::spawn(move || {
|
||||||
tx.send(some_expensive_computation(init_val));
|
tx.send(some_expensive_computation(init_val));
|
||||||
});
|
});
|
||||||
rx
|
rx
|
||||||
});
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Wait on each port, accumulating the results
|
// Wait on each port, accumulating the results
|
||||||
let result = rxs.iter().fold(0, |accum, rx| accum + rx.recv() );
|
let result = rxs.iter().fold(0, |&:accum, rx| accum + rx.recv().unwrap() );
|
||||||
# fn some_expensive_computation(_i: uint) -> int { 42 }
|
# fn some_expensive_computation(_i: u32) -> u32 { 42 }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Backgrounding computations: Futures
|
## Backgrounding computations: Futures
|
||||||
@ -212,7 +224,7 @@ use std::sync::Future;
|
|||||||
# fn main() {
|
# fn main() {
|
||||||
# fn make_a_sandwich() {};
|
# fn make_a_sandwich() {};
|
||||||
fn fib(n: u64) -> u64 {
|
fn fib(n: u64) -> u64 {
|
||||||
// lengthy computation returning an uint
|
// lengthy computation returning an 64
|
||||||
12586269025
|
12586269025
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +249,7 @@ computations. The workload will be distributed on the available cores.
|
|||||||
# #![allow(deprecated)]
|
# #![allow(deprecated)]
|
||||||
# use std::num::Float;
|
# use std::num::Float;
|
||||||
# use std::sync::Future;
|
# use std::sync::Future;
|
||||||
fn partial_sum(start: uint) -> f64 {
|
fn partial_sum(start: u64) -> f64 {
|
||||||
let mut local_sum = 0f64;
|
let mut local_sum = 0f64;
|
||||||
for num in range(start*100000, (start+1)*100000) {
|
for num in range(start*100000, (start+1)*100000) {
|
||||||
local_sum += (num as f64 + 1.0).powf(-2.0);
|
local_sum += (num as f64 + 1.0).powf(-2.0);
|
||||||
@ -277,7 +289,7 @@ use std::num::Float;
|
|||||||
use std::rand;
|
use std::rand;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
fn pnorm(nums: &[f64], p: uint) -> f64 {
|
fn pnorm(nums: &[f64], p: u64) -> f64 {
|
||||||
nums.iter().fold(0.0, |a, b| a + b.powf(p as f64)).powf(1.0 / (p as f64))
|
nums.iter().fold(0.0, |a, b| a + b.powf(p as f64)).powf(1.0 / (p as f64))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +297,7 @@ fn main() {
|
|||||||
let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
|
let numbers = Vec::from_fn(1000000, |_| rand::random::<f64>());
|
||||||
let numbers_arc = Arc::new(numbers);
|
let numbers_arc = Arc::new(numbers);
|
||||||
|
|
||||||
for num in range(1u, 10) {
|
for num in range(1, 10) {
|
||||||
let thread_numbers = numbers_arc.clone();
|
let thread_numbers = numbers_arc.clone();
|
||||||
|
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
@ -316,7 +328,7 @@ if it were local.
|
|||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
# use std::rand;
|
# use std::rand;
|
||||||
# use std::sync::Arc;
|
# use std::sync::Arc;
|
||||||
# fn pnorm(nums: &[f64], p: uint) -> f64 { 4.0 }
|
# fn pnorm(nums: &[f64], p: u64) -> f64 { 4.0 }
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
|
# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
|
||||||
# let numbers_arc = Arc::new(numbers);
|
# let numbers_arc = Arc::new(numbers);
|
||||||
@ -345,16 +357,16 @@ each other if they panic. The simplest way of handling a panic is with the
|
|||||||
`try` function, which is similar to `spawn`, but immediately blocks and waits
|
`try` function, which is similar to `spawn`, but immediately blocks and waits
|
||||||
for the child thread to finish. `try` returns a value of type
|
for the child thread to finish. `try` returns a value of type
|
||||||
`Result<T, Box<Any + Send>>`. `Result` is an `enum` type with two variants:
|
`Result<T, Box<Any + Send>>`. `Result` is an `enum` type with two variants:
|
||||||
`Ok` and `Err`. In this case, because the type arguments to `Result` are `int`
|
`Ok` and `Err`. In this case, because the type arguments to `Result` are `i32`
|
||||||
and `()`, callers can pattern-match on a result to check whether it's an `Ok`
|
and `()`, callers can pattern-match on a result to check whether it's an `Ok`
|
||||||
result with an `int` field (representing a successful result) or an `Err` result
|
result with an `i32` field (representing a successful result) or an `Err` result
|
||||||
(representing termination with an error).
|
(representing termination with an error).
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
# use std::thread::Thread;
|
# use std::thread::Thread;
|
||||||
# fn some_condition() -> bool { false }
|
# fn some_condition() -> bool { false }
|
||||||
# fn calculate_result() -> int { 0 }
|
# fn calculate_result() -> i32 { 0 }
|
||||||
let result: Result<int, Box<std::any::Any + Send>> = Thread::spawn(move || {
|
let result: Result<i32, Box<std::any::Any + Send>> = Thread::spawn(move || {
|
||||||
if some_condition() {
|
if some_condition() {
|
||||||
calculate_result()
|
calculate_result()
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,7 +145,7 @@ As you can see, `print_area` is now generic, but also ensures that we
|
|||||||
have passed in the correct types. If we pass in an incorrect type:
|
have passed in the correct types. If we pass in an incorrect type:
|
||||||
|
|
||||||
```{rust,ignore}
|
```{rust,ignore}
|
||||||
print_area(5i);
|
print_area(5);
|
||||||
```
|
```
|
||||||
|
|
||||||
We get a compile-time error:
|
We get a compile-time error:
|
||||||
@ -156,14 +156,14 @@ error: failed to find an implementation of trait main::HasArea for int
|
|||||||
|
|
||||||
So far, we've only added trait implementations to structs, but you can
|
So far, we've only added trait implementations to structs, but you can
|
||||||
implement a trait for any type. So technically, we _could_ implement
|
implement a trait for any type. So technically, we _could_ implement
|
||||||
`HasArea` for `int`:
|
`HasArea` for `i32`:
|
||||||
|
|
||||||
```{rust}
|
```{rust}
|
||||||
trait HasArea {
|
trait HasArea {
|
||||||
fn area(&self) -> f64;
|
fn area(&self) -> f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasArea for int {
|
impl HasArea for i32 {
|
||||||
fn area(&self) -> f64 {
|
fn area(&self) -> f64 {
|
||||||
println!("this is silly");
|
println!("this is silly");
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ impl HasArea for int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
5i.area();
|
5.area();
|
||||||
```
|
```
|
||||||
|
|
||||||
It is considered poor style to implement methods on such primitive types, even
|
It is considered poor style to implement methods on such primitive types, even
|
||||||
@ -264,8 +264,8 @@ it won't affect you, unless you `use` that trait.
|
|||||||
|
|
||||||
There's one more restriction on implementing traits. Either the trait or the
|
There's one more restriction on implementing traits. Either the trait or the
|
||||||
type you're writing the `impl` for must be inside your crate. So, we could
|
type you're writing the `impl` for must be inside your crate. So, we could
|
||||||
implement the `HasArea` type for `int`, because `HasArea` is in our crate. But
|
implement the `HasArea` type for `i32`, because `HasArea` is in our crate. But
|
||||||
if we tried to implement `Float`, a trait provided by Rust, for `int`, we could
|
if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could
|
||||||
not, because both the trait and the type aren't in our crate.
|
not, because both the trait and the type aren't in our crate.
|
||||||
|
|
||||||
One last thing about traits: generic functions with a trait bound use
|
One last thing about traits: generic functions with a trait bound use
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% Writing Unsafe and Low-Level Code in Rust
|
% Unsafe and Low-Level Code
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ offered by the Rust language and libraries. For example, they
|
|||||||
use-after-free;
|
use-after-free;
|
||||||
- are considered sendable (if their contents is considered sendable),
|
- are considered sendable (if their contents is considered sendable),
|
||||||
so the compiler offers no assistance with ensuring their use is
|
so the compiler offers no assistance with ensuring their use is
|
||||||
thread-safe; for example, one can concurrently access a `*mut int`
|
thread-safe; for example, one can concurrently access a `*mut i32`
|
||||||
from two threads without synchronization.
|
from two threads without synchronization.
|
||||||
- lack any form of lifetimes, unlike `&`, and so the compiler cannot
|
- lack any form of lifetimes, unlike `&`, and so the compiler cannot
|
||||||
reason about dangling pointers; and
|
reason about dangling pointers; and
|
||||||
@ -265,12 +265,12 @@ impl<T: Send> Drop for Unique<T> {
|
|||||||
// A comparison between the built-in `Box` and this reimplementation
|
// A comparison between the built-in `Box` and this reimplementation
|
||||||
fn main() {
|
fn main() {
|
||||||
{
|
{
|
||||||
let mut x = Box::new(5i);
|
let mut x = Box::new(5);
|
||||||
*x = 10;
|
*x = 10;
|
||||||
} // `x` is freed here
|
} // `x` is freed here
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut y = Unique::new(5i);
|
let mut y = Unique::new(5);
|
||||||
*y.borrow_mut() = 10;
|
*y.borrow_mut() = 10;
|
||||||
} // `y` is freed here
|
} // `y` is freed here
|
||||||
}
|
}
|
||||||
@ -367,7 +367,7 @@ expressions must be mutable lvalues:
|
|||||||
```
|
```
|
||||||
# #![feature(asm)]
|
# #![feature(asm)]
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
fn add(a: int, b: int) -> int {
|
fn add(a: i32, b: i32) -> i32 {
|
||||||
let mut c = 0;
|
let mut c = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("add $2, $0"
|
asm!("add $2, $0"
|
||||||
@ -378,7 +378,7 @@ fn add(a: int, b: int) -> int {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
# fn add(a: int, b: int) -> int { a + b }
|
# fn add(a: i32, b: i32) -> i32 { a + b }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(add(3, 14159), 14162)
|
assert_eq!(add(3, 14159), 14162)
|
||||||
@ -454,7 +454,7 @@ extern crate libc;
|
|||||||
|
|
||||||
// Entry point for this program
|
// Entry point for this program
|
||||||
#[start]
|
#[start]
|
||||||
fn start(_argc: int, _argv: *const *const u8) -> int {
|
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +480,7 @@ compiler's name mangling too:
|
|||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
#[no_mangle] // ensure that this symbol is called `main` in the output
|
#[no_mangle] // ensure that this symbol is called `main` in the output
|
||||||
pub extern fn main(argc: int, argv: *const *const u8) -> int {
|
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,8 +552,8 @@ pub extern fn dot_product(a: *const u32, a_len: u32,
|
|||||||
// cannot tell the pointers are valid.
|
// cannot tell the pointers are valid.
|
||||||
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
|
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
|
||||||
mem::transmute((
|
mem::transmute((
|
||||||
Slice { data: a, len: a_len as uint },
|
Slice { data: a, len: a_len as usize },
|
||||||
Slice { data: b, len: b_len as uint },
|
Slice { data: b, len: b_len as usize },
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -567,14 +567,14 @@ pub extern fn dot_product(a: *const u32, a_len: u32,
|
|||||||
|
|
||||||
#[lang = "panic_fmt"]
|
#[lang = "panic_fmt"]
|
||||||
extern fn panic_fmt(args: &core::fmt::Arguments,
|
extern fn panic_fmt(args: &core::fmt::Arguments,
|
||||||
file: &str,
|
file: &str,
|
||||||
line: uint) -> ! {
|
line: u32) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||||
# #[start] fn start(argc: int, argv: *const *const u8) -> int { 0 }
|
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -628,7 +628,7 @@ via a declaration like
|
|||||||
extern "rust-intrinsic" {
|
extern "rust-intrinsic" {
|
||||||
fn transmute<T, U>(x: T) -> U;
|
fn transmute<T, U>(x: T) -> U;
|
||||||
|
|
||||||
fn offset<T>(dst: *const T, offset: int) -> *const T;
|
fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -665,24 +665,24 @@ extern {
|
|||||||
pub struct Box<T>(*mut T);
|
pub struct Box<T>(*mut T);
|
||||||
|
|
||||||
#[lang="exchange_malloc"]
|
#[lang="exchange_malloc"]
|
||||||
unsafe fn allocate(size: uint, _align: uint) -> *mut u8 {
|
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
||||||
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
||||||
|
|
||||||
// malloc failed
|
// malloc failed
|
||||||
if p as uint == 0 {
|
if p as usize == 0 {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
#[lang="exchange_free"]
|
#[lang="exchange_free"]
|
||||||
unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
|
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
|
||||||
libc::free(ptr as *mut libc::c_void)
|
libc::free(ptr as *mut libc::c_void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn main(argc: int, argv: *const *const u8) -> int {
|
fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||||
let x = box 1i;
|
let x = box 1;
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
% Variable bindings
|
% Variable Bindings
|
||||||
|
|
||||||
The first thing we'll learn about are *variable bindings*. They look like this:
|
The first thing we'll learn about are *variable bindings*. They look like this:
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ static FALSE: bool = false;
|
|||||||
/// println!("{:?}", bv);
|
/// println!("{:?}", bv);
|
||||||
/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
|
/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
|
||||||
/// ```
|
/// ```
|
||||||
#[stable]
|
#[unstable = "RFC 509"]
|
||||||
pub struct Bitv {
|
pub struct Bitv {
|
||||||
/// Internal representation of the bit vector
|
/// Internal representation of the bit vector
|
||||||
storage: Vec<u32>,
|
storage: Vec<u32>,
|
||||||
@ -1107,7 +1107,7 @@ impl<'a> RandomAccessIterator for Iter<'a> {
|
|||||||
/// assert!(bv[3]);
|
/// assert!(bv[3]);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[stable]
|
#[unstable = "RFC 509"]
|
||||||
pub struct BitvSet {
|
pub struct BitvSet {
|
||||||
bitv: Bitv,
|
bitv: Bitv,
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,12 @@ pub mod string;
|
|||||||
pub mod vec;
|
pub mod vec;
|
||||||
pub mod vec_map;
|
pub mod vec_map;
|
||||||
|
|
||||||
#[stable]
|
#[unstable = "RFC 509"]
|
||||||
pub mod bitv {
|
pub mod bitv {
|
||||||
pub use bit::{Bitv, Iter};
|
pub use bit::{Bitv, Iter};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable]
|
#[unstable = "RFC 509"]
|
||||||
pub mod bitv_set {
|
pub mod bitv_set {
|
||||||
pub use bit::{BitvSet, Union, Intersection, Difference, SymmetricDifference};
|
pub use bit::{BitvSet, Union, Intersection, Difference, SymmetricDifference};
|
||||||
pub use bit::SetIter as Iter;
|
pub use bit::SetIter as Iter;
|
||||||
|
@ -115,7 +115,6 @@
|
|||||||
//! }
|
//! }
|
||||||
//! # fn calc_span_tree(&self) -> Vec<(uint, uint)> { vec![] }
|
//! # fn calc_span_tree(&self) -> Vec<(uint, uint)> { vec![] }
|
||||||
//! }
|
//! }
|
||||||
//! # fn main() { }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Mutating implementations of `clone`
|
//! ## Mutating implementations of `clone`
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
//!
|
//!
|
||||||
//! use std::finally::Finally;
|
//! use std::finally::Finally;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
|
||||||
//! (|&mut:| {
|
//! (|&mut:| {
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }).finally(|| {
|
//! }).finally(|| {
|
||||||
//! // this code is always run
|
//! // this code is always run
|
||||||
//! })
|
//! })
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![deprecated = "It is unclear if this module is more robust than implementing \
|
#![deprecated = "It is unclear if this module is more robust than implementing \
|
||||||
|
@ -39,13 +39,16 @@ macro_rules! panic {
|
|||||||
/// // the panic message for these assertions is the stringified value of the
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
/// // expression given.
|
/// // expression given.
|
||||||
/// assert!(true);
|
/// assert!(true);
|
||||||
/// # fn some_computation() -> bool { true }
|
///
|
||||||
|
/// fn some_computation() -> bool { true } // a very simple function
|
||||||
|
///
|
||||||
/// assert!(some_computation());
|
/// assert!(some_computation());
|
||||||
///
|
///
|
||||||
/// // assert with a custom message
|
/// // assert with a custom message
|
||||||
/// # let x = true;
|
/// let x = true;
|
||||||
/// assert!(x, "x wasn't true!");
|
/// assert!(x, "x wasn't true!");
|
||||||
/// # let a = 3i; let b = 27i;
|
///
|
||||||
|
/// let a = 3i; let b = 27i;
|
||||||
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
|
/// assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -108,13 +111,15 @@ macro_rules! assert_eq {
|
|||||||
/// // the panic message for these assertions is the stringified value of the
|
/// // the panic message for these assertions is the stringified value of the
|
||||||
/// // expression given.
|
/// // expression given.
|
||||||
/// debug_assert!(true);
|
/// debug_assert!(true);
|
||||||
/// # fn some_expensive_computation() -> bool { true }
|
///
|
||||||
|
/// fn some_expensive_computation() -> bool { true } // a very simple function
|
||||||
/// debug_assert!(some_expensive_computation());
|
/// debug_assert!(some_expensive_computation());
|
||||||
///
|
///
|
||||||
/// // assert with a custom message
|
/// // assert with a custom message
|
||||||
/// # let x = true;
|
/// let x = true;
|
||||||
/// debug_assert!(x, "x wasn't true!");
|
/// debug_assert!(x, "x wasn't true!");
|
||||||
/// # let a = 3i; let b = 27i;
|
///
|
||||||
|
/// let a = 3; let b = 27;
|
||||||
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
|
/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b);
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -42,6 +42,104 @@ pub trait Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||||
|
///
|
||||||
|
/// By default, variable bindings have 'move semantics.' In other
|
||||||
|
/// words:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #[derive(Show)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// let x = Foo;
|
||||||
|
///
|
||||||
|
/// let y = x;
|
||||||
|
///
|
||||||
|
/// // `x` has moved into `y`, and so cannot be used
|
||||||
|
///
|
||||||
|
/// // println!("{:?}", x); // error: use of moved value
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// However, if a type implements `Copy`, it instead has 'copy semantics':
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// // we can just derive a `Copy` implementation
|
||||||
|
/// #[derive(Show, Copy)]
|
||||||
|
/// struct Foo;
|
||||||
|
///
|
||||||
|
/// let x = Foo;
|
||||||
|
///
|
||||||
|
/// let y = x;
|
||||||
|
///
|
||||||
|
/// // `y` is a copy of `x`
|
||||||
|
///
|
||||||
|
/// println!("{:?}", x); // A-OK!
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// It's important to note that in these two examples, the only difference is if you are allowed to
|
||||||
|
/// access `x` after the assignment: a move is also a bitwise copy under the hood.
|
||||||
|
///
|
||||||
|
/// ## When can my type be `Copy`?
|
||||||
|
///
|
||||||
|
/// A type can implement `Copy` if all of its components implement `Copy`. For example, this
|
||||||
|
/// `struct` can be `Copy`:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// struct Point {
|
||||||
|
/// x: i32,
|
||||||
|
/// y: i32,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # struct Point;
|
||||||
|
/// struct PointList {
|
||||||
|
/// points: Vec<Point>,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `PointList` `struct` cannot implement `Copy`, because `Vec<T>` is not `Copy`. If we
|
||||||
|
/// attempt to derive a `Copy` implementation, we'll get an error.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// error: the trait `Copy` may not be implemented for this type; field `points` does not implement
|
||||||
|
/// `Copy`
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## How can I implement `Copy`?
|
||||||
|
///
|
||||||
|
/// There are two ways to implement `Copy` on your type:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #[derive(Copy)]
|
||||||
|
/// struct MyStruct;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// and
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// struct MyStruct;
|
||||||
|
/// impl Copy for MyStruct {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||||
|
/// bound on type parameters, which isn't always desired.
|
||||||
|
///
|
||||||
|
/// ## When can my type _not_ be `Copy`?
|
||||||
|
///
|
||||||
|
/// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
|
||||||
|
/// mutable reference, and copying `String` would result in two attempts to free the same buffer.
|
||||||
|
///
|
||||||
|
/// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's
|
||||||
|
/// managing some resource besides its own `size_of::<T>()` bytes.
|
||||||
|
///
|
||||||
|
/// ## When should my type be `Copy`?
|
||||||
|
///
|
||||||
|
/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing
|
||||||
|
/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future,
|
||||||
|
/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking
|
||||||
|
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
|
||||||
#[stable]
|
#[stable]
|
||||||
#[lang="copy"]
|
#[lang="copy"]
|
||||||
pub trait Copy {
|
pub trait Copy {
|
||||||
@ -210,8 +308,7 @@ impl<T: ?Sized> Clone for ContravariantType<T> {
|
|||||||
/// "interior" mutability:
|
/// "interior" mutability:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// pub struct Cell<T> { value: T }
|
/// struct Cell<T> { value: T }
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The type system would infer that `value` is only read here and
|
/// The type system would infer that `value` is only read here and
|
||||||
|
@ -830,28 +830,27 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// A trivial implementation of `Index`. When `Foo[Foo]` happens, it ends up
|
/// A trivial implementation of `Index`. When `Foo[Bar]` happens, it ends up
|
||||||
/// calling `index`, and therefore, `main` prints `Indexing!`.
|
/// calling `index`, and therefore, `main` prints `Indexing!`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(associated_types)]
|
|
||||||
///
|
|
||||||
/// use std::ops::Index;
|
/// use std::ops::Index;
|
||||||
///
|
///
|
||||||
/// #[derive(Copy)]
|
/// #[derive(Copy)]
|
||||||
/// struct Foo;
|
/// struct Foo;
|
||||||
|
/// struct Bar;
|
||||||
///
|
///
|
||||||
/// impl Index<Foo> for Foo {
|
/// impl Index<Bar> for Foo {
|
||||||
/// type Output = Foo;
|
/// type Output = Foo;
|
||||||
///
|
///
|
||||||
/// fn index<'a>(&'a self, _index: &Foo) -> &'a Foo {
|
/// fn index<'a>(&'a self, _index: &Bar) -> &'a Foo {
|
||||||
/// println!("Indexing!");
|
/// println!("Indexing!");
|
||||||
/// self
|
/// self
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// Foo[Foo];
|
/// Foo[Bar];
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[lang="index"]
|
#[lang="index"]
|
||||||
@ -867,28 +866,27 @@ pub trait Index<Index: ?Sized> {
|
|||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// A trivial implementation of `IndexMut`. When `Foo[Foo]` happens, it ends up
|
/// A trivial implementation of `IndexMut`. When `Foo[Bar]` happens, it ends up
|
||||||
/// calling `index_mut`, and therefore, `main` prints `Indexing!`.
|
/// calling `index_mut`, and therefore, `main` prints `Indexing!`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(associated_types)]
|
|
||||||
///
|
|
||||||
/// use std::ops::IndexMut;
|
/// use std::ops::IndexMut;
|
||||||
///
|
///
|
||||||
/// #[derive(Copy)]
|
/// #[derive(Copy)]
|
||||||
/// struct Foo;
|
/// struct Foo;
|
||||||
|
/// struct Bar;
|
||||||
///
|
///
|
||||||
/// impl IndexMut<Foo> for Foo {
|
/// impl IndexMut<Bar> for Foo {
|
||||||
/// type Output = Foo;
|
/// type Output = Foo;
|
||||||
///
|
///
|
||||||
/// fn index_mut<'a>(&'a mut self, _index: &Foo) -> &'a mut Foo {
|
/// fn index_mut<'a>(&'a mut self, _index: &Bar) -> &'a mut Foo {
|
||||||
/// println!("Indexing!");
|
/// println!("Indexing!");
|
||||||
/// self
|
/// self
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// &mut Foo[Foo];
|
/// &mut Foo[Bar];
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[lang="index_mut"]
|
#[lang="index_mut"]
|
||||||
|
@ -21,11 +21,7 @@
|
|||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
//! # fn main() {
|
|
||||||
//! #![feature(globs)]
|
|
||||||
//!
|
|
||||||
//! use core::prelude::*;
|
//! use core::prelude::*;
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
// Reexported core operators
|
// Reexported core operators
|
||||||
|
@ -217,11 +217,9 @@
|
|||||||
//! makes it clear:
|
//! makes it clear:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #![feature(macro_rules)]
|
|
||||||
//! macro_rules! try {
|
//! macro_rules! try {
|
||||||
//! ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
//! ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
|
||||||
//! }
|
//! }
|
||||||
//! # fn main() { }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! `try!` is imported by the prelude, and is available everywhere.
|
//! `try!` is imported by the prelude, and is available everywhere.
|
||||||
|
@ -4168,6 +4168,27 @@ pub mod funcs {
|
|||||||
pub fn malloc(size: size_t) -> *mut c_void;
|
pub fn malloc(size: size_t) -> *mut c_void;
|
||||||
pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
|
pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
|
||||||
pub fn free(p: *mut c_void);
|
pub fn free(p: *mut c_void);
|
||||||
|
|
||||||
|
/// Exits the running program in a possibly dangerous manner.
|
||||||
|
///
|
||||||
|
/// # Unsafety
|
||||||
|
///
|
||||||
|
/// While this forces your program to exit, it does so in a way that has
|
||||||
|
/// consequences. This will skip all unwinding code, which means that anything
|
||||||
|
/// relying on unwinding for cleanup (such as flushing and closing a buffer to a
|
||||||
|
/// file) may act in an unexpected way.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// extern crate libc;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// unsafe {
|
||||||
|
/// libc::exit(1);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn exit(status: c_int) -> !;
|
pub fn exit(status: c_int) -> !;
|
||||||
pub fn _exit(status: c_int) -> !;
|
pub fn _exit(status: c_int) -> !;
|
||||||
pub fn atexit(cb: extern fn()) -> c_int;
|
pub fn atexit(cb: extern fn()) -> c_int;
|
||||||
|
@ -44,6 +44,7 @@ extern crate rbml;
|
|||||||
extern crate collections;
|
extern crate collections;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|
||||||
extern crate "serialize" as rustc_serialize; // used by deriving
|
extern crate "serialize" as rustc_serialize; // used by deriving
|
||||||
|
|
||||||
|
@ -8,10 +8,16 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![crate_name = "rustc_bitflags"]
|
||||||
#![unstable]
|
#![unstable]
|
||||||
|
#![staged_api]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
//! A typesafe bitmask flag generator.
|
//! A typesafe bitmask flag generator.
|
||||||
|
|
||||||
|
#[cfg(test)] #[macro_use] extern crate std;
|
||||||
|
|
||||||
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
|
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
|
||||||
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
|
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
|
||||||
///
|
///
|
||||||
@ -21,6 +27,8 @@
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```{.rust}
|
/// ```{.rust}
|
||||||
|
/// #[macro_use] extern crate rustc_bitflags;
|
||||||
|
///
|
||||||
/// bitflags! {
|
/// bitflags! {
|
||||||
/// flags Flags: u32 {
|
/// flags Flags: u32 {
|
||||||
/// const FLAG_A = 0b00000001,
|
/// const FLAG_A = 0b00000001,
|
||||||
@ -45,6 +53,8 @@
|
|||||||
/// The generated `struct`s can also be extended with type and trait implementations:
|
/// The generated `struct`s can also be extended with type and trait implementations:
|
||||||
///
|
///
|
||||||
/// ```{.rust}
|
/// ```{.rust}
|
||||||
|
/// #[macro_use] extern crate rustc_bitflags;
|
||||||
|
///
|
||||||
/// use std::fmt;
|
/// use std::fmt;
|
||||||
///
|
///
|
||||||
/// bitflags! {
|
/// bitflags! {
|
||||||
@ -273,8 +283,8 @@ macro_rules! bitflags {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use hash::{self, SipHasher};
|
use std::hash::{self, SipHasher};
|
||||||
use option::Option::{Some, None};
|
use std::option::Option::{Some, None};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[doc = "> The first principle is that you must not fool yourself — and"]
|
#[doc = "> The first principle is that you must not fool yourself — and"]
|
@ -28,6 +28,7 @@
|
|||||||
#![allow(unknown_features)] #![feature(int_uint)]
|
#![allow(unknown_features)] #![feature(int_uint)]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|
||||||
pub use self::OtherAttribute::*;
|
pub use self::OtherAttribute::*;
|
||||||
pub use self::SpecialAttribute::*;
|
pub use self::SpecialAttribute::*;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
|
|
||||||
|
@ -26,15 +26,13 @@
|
|||||||
//!
|
//!
|
||||||
//! Some examples of the `format!` extension are:
|
//! Some examples of the `format!` extension are:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```
|
||||||
//! # fn main() {
|
|
||||||
//! format!("Hello"); // => "Hello"
|
//! format!("Hello"); // => "Hello"
|
||||||
//! format!("Hello, {}!", "world"); // => "Hello, world!"
|
//! format!("Hello, {}!", "world"); // => "Hello, world!"
|
||||||
//! format!("The number is {}", 1i); // => "The number is 1"
|
//! format!("The number is {}", 1i); // => "The number is 1"
|
||||||
//! format!("{:?}", (3i, 4i)); // => "(3i, 4i)"
|
//! format!("{:?}", (3i, 4i)); // => "(3i, 4i)"
|
||||||
//! format!("{value}", value=4i); // => "4"
|
//! format!("{value}", value=4i); // => "4"
|
||||||
//! format!("{} {}", 1i, 2u); // => "1 2"
|
//! format!("{} {}", 1i, 2u); // => "1 2"
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! From these, you can see that the first argument is a format string. It is
|
//! From these, you can see that the first argument is a format string. It is
|
||||||
@ -83,12 +81,10 @@
|
|||||||
//!
|
//!
|
||||||
//! For example, the following `format!` expressions all use named argument:
|
//! For example, the following `format!` expressions all use named argument:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```
|
||||||
//! # fn main() {
|
|
||||||
//! format!("{argument}", argument = "test"); // => "test"
|
//! format!("{argument}", argument = "test"); // => "test"
|
||||||
//! format!("{name} {}", 1i, name = 2i); // => "2 1"
|
//! format!("{name} {}", 1i, name = 2i); // => "2 1"
|
||||||
//! format!("{a} {c} {b}", a="a", b='b', c=3i); // => "a 3 b"
|
//! format!("{a} {c} {b}", a="a", b='b', c=3i); // => "a 3 b"
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! It is illegal to put positional parameters (those without names) after
|
//! It is illegal to put positional parameters (those without names) after
|
||||||
@ -288,8 +284,6 @@
|
|||||||
//! use std::fmt;
|
//! use std::fmt;
|
||||||
//! use std::io;
|
//! use std::io;
|
||||||
//!
|
//!
|
||||||
//! # #[allow(unused_must_use)]
|
|
||||||
//! # fn main() {
|
|
||||||
//! fmt::format(format_args!("this returns {}", "String"));
|
//! fmt::format(format_args!("this returns {}", "String"));
|
||||||
//!
|
//!
|
||||||
//! let some_writer: &mut io::Writer = &mut io::stdout();
|
//! let some_writer: &mut io::Writer = &mut io::stdout();
|
||||||
@ -299,7 +293,6 @@
|
|||||||
//! write!(&mut io::stdout(), "{}", args);
|
//! write!(&mut io::stdout(), "{}", args);
|
||||||
//! }
|
//! }
|
||||||
//! my_fmt_fn(format_args!("or a {} too", "function"));
|
//! my_fmt_fn(format_args!("or a {} too", "function"));
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The result of the `format_args!` macro is a value of type `fmt::Arguments`.
|
//! The result of the `format_args!` macro is a value of type `fmt::Arguments`.
|
||||||
|
@ -934,16 +934,15 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
|
|||||||
/// A `RefReader` is a struct implementing `Reader` which contains a reference
|
/// A `RefReader` is a struct implementing `Reader` which contains a reference
|
||||||
/// to another reader. This is often useful when composing streams.
|
/// to another reader. This is often useful when composing streams.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn process_input<R: Reader>(r: R) {}
|
|
||||||
/// # fn foo() {
|
|
||||||
/// use std::io;
|
/// use std::io;
|
||||||
/// use std::io::ByRefReader;
|
/// use std::io::ByRefReader;
|
||||||
/// use std::io::util::LimitReader;
|
/// use std::io::util::LimitReader;
|
||||||
///
|
///
|
||||||
|
/// fn process_input<R: Reader>(r: R) {}
|
||||||
|
///
|
||||||
/// let mut stream = io::stdin();
|
/// let mut stream = io::stdin();
|
||||||
///
|
///
|
||||||
/// // Only allow the function to process at most one kilobyte of input
|
/// // Only allow the function to process at most one kilobyte of input
|
||||||
@ -953,8 +952,6 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // 'stream' is still available for use here
|
/// // 'stream' is still available for use here
|
||||||
///
|
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub struct RefReader<'a, R:'a> {
|
pub struct RefReader<'a, R:'a> {
|
||||||
/// The underlying reader which this is referencing
|
/// The underlying reader which this is referencing
|
||||||
@ -1269,12 +1266,11 @@ impl<'a> Writer for &'a mut (Writer+'a) {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn process_input<R: Reader>(r: R) {}
|
|
||||||
/// # fn foo () {
|
|
||||||
/// use std::io::util::TeeReader;
|
/// use std::io::util::TeeReader;
|
||||||
/// use std::io::{stdin, ByRefWriter};
|
/// use std::io::{stdin, ByRefWriter};
|
||||||
///
|
///
|
||||||
|
/// fn process_input<R: Reader>(r: R) {}
|
||||||
|
///
|
||||||
/// let mut output = Vec::new();
|
/// let mut output = Vec::new();
|
||||||
///
|
///
|
||||||
/// {
|
/// {
|
||||||
@ -1285,7 +1281,6 @@ impl<'a> Writer for &'a mut (Writer+'a) {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// println!("input processed: {:?}", output);
|
/// println!("input processed: {:?}", output);
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub struct RefWriter<'a, W:'a> {
|
pub struct RefWriter<'a, W:'a> {
|
||||||
/// The underlying writer which this is referencing
|
/// The underlying writer which this is referencing
|
||||||
@ -1705,19 +1700,19 @@ pub enum FileType {
|
|||||||
/// A structure used to describe metadata information about a file. This
|
/// A structure used to describe metadata information about a file. This
|
||||||
/// structure is created through the `stat` method on a `Path`.
|
/// structure is created through the `stat` method on a `Path`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # #![allow(unstable)]
|
||||||
|
///
|
||||||
|
/// use std::io::fs::PathExtensions;
|
||||||
///
|
///
|
||||||
/// ```
|
|
||||||
/// # use std::io::fs::PathExtensions;
|
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn foo() {
|
|
||||||
/// let info = match Path::new("foo.txt").stat() {
|
/// let info = match Path::new("foo.txt").stat() {
|
||||||
/// Ok(stat) => stat,
|
/// Ok(stat) => stat,
|
||||||
/// Err(e) => panic!("couldn't read foo.txt: {}", e),
|
/// Err(e) => panic!("couldn't read foo.txt: {}", e),
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// println!("byte size: {}", info.size);
|
/// println!("byte size: {}", info.size);
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Copy, Hash)]
|
#[derive(Copy, Hash)]
|
||||||
pub struct FileStat {
|
pub struct FileStat {
|
||||||
|
@ -168,9 +168,7 @@ impl UnixListener {
|
|||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn foo() {
|
/// # fn foo() {
|
||||||
/// # #![allow(unused_must_use)]
|
|
||||||
/// use std::io::net::pipe::UnixListener;
|
/// use std::io::net::pipe::UnixListener;
|
||||||
/// use std::io::{Listener, Acceptor};
|
/// use std::io::{Listener, Acceptor};
|
||||||
///
|
///
|
||||||
|
@ -272,12 +272,10 @@ impl sys_common::AsInner<TcpStreamImp> for TcpStream {
|
|||||||
/// A structure representing a socket server. This listener is used to create a
|
/// A structure representing a socket server. This listener is used to create a
|
||||||
/// `TcpAcceptor` which can be used to accept sockets on a local port.
|
/// `TcpAcceptor` which can be used to accept sockets on a local port.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```
|
||||||
/// # fn main() { }
|
|
||||||
/// # fn foo() {
|
/// # fn foo() {
|
||||||
/// # #![allow(dead_code)]
|
|
||||||
/// use std::io::{TcpListener, TcpStream};
|
/// use std::io::{TcpListener, TcpStream};
|
||||||
/// use std::io::{Acceptor, Listener};
|
/// use std::io::{Acceptor, Listener};
|
||||||
/// use std::thread::Thread;
|
/// use std::thread::Thread;
|
||||||
|
@ -27,10 +27,9 @@ use sys::timer::Timer as TimerImp;
|
|||||||
/// period of time. Handles to this timer can also be created in the form of
|
/// period of time. Handles to this timer can also be created in the form of
|
||||||
/// receivers which will receive notifications over time.
|
/// receivers which will receive notifications over time.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn foo() {
|
/// # fn foo() {
|
||||||
/// use std::io::Timer;
|
/// use std::io::Timer;
|
||||||
/// use std::time::Duration;
|
/// use std::time::Duration;
|
||||||
@ -54,7 +53,6 @@ use sys::timer::Timer as TimerImp;
|
|||||||
/// the `io::timer` module.
|
/// the `io::timer` module.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() {}
|
|
||||||
/// # fn foo() {
|
/// # fn foo() {
|
||||||
/// use std::io::timer;
|
/// use std::io::timer;
|
||||||
/// use std::time::Duration;
|
/// use std::time::Duration;
|
||||||
|
@ -111,7 +111,7 @@
|
|||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(old_impl_check)]
|
#![feature(old_impl_check)]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
#![allow(unknown_features)] #![feature(int_uint)]
|
#![feature(int_uint)]
|
||||||
|
|
||||||
// Don't link to std. We are std.
|
// Don't link to std. We are std.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@ -136,6 +136,8 @@ extern crate alloc;
|
|||||||
extern crate unicode;
|
extern crate unicode;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|
||||||
// Make std testable by not duplicating lang items. See #2912
|
// Make std testable by not duplicating lang items. See #2912
|
||||||
#[cfg(test)] extern crate "std" as realstd;
|
#[cfg(test)] extern crate "std" as realstd;
|
||||||
#[cfg(test)] pub use realstd::marker;
|
#[cfg(test)] pub use realstd::marker;
|
||||||
@ -181,9 +183,6 @@ pub use unicode::char;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod bitflags;
|
|
||||||
|
|
||||||
mod rtdeps;
|
mod rtdeps;
|
||||||
|
|
||||||
/* The Prelude. */
|
/* The Prelude. */
|
||||||
|
@ -122,16 +122,18 @@ macro_rules! try {
|
|||||||
/// receivers. It places no restrictions on the types of receivers given to
|
/// receivers. It places no restrictions on the types of receivers given to
|
||||||
/// this macro, this can be viewed as a heterogeneous select.
|
/// this macro, this can be viewed as a heterogeneous select.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::thread::Thread;
|
/// use std::thread::Thread;
|
||||||
/// use std::sync::mpsc::channel;
|
/// use std::sync::mpsc;
|
||||||
///
|
///
|
||||||
/// let (tx1, rx1) = channel();
|
/// // two placeholder functions for now
|
||||||
/// let (tx2, rx2) = channel();
|
/// fn long_running_task() {}
|
||||||
/// # fn long_running_task() {}
|
/// fn calculate_the_answer() -> u32 { 42 }
|
||||||
/// # fn calculate_the_answer() -> int { 42i }
|
///
|
||||||
|
/// let (tx1, rx1) = mpsc::channel();
|
||||||
|
/// let (tx2, rx2) = mpsc::channel();
|
||||||
///
|
///
|
||||||
/// Thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); });
|
/// Thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); });
|
||||||
/// Thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); });
|
/// Thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); });
|
||||||
@ -251,13 +253,13 @@ pub mod builtin {
|
|||||||
/// statement or expression position, meaning this macro may be difficult to
|
/// statement or expression position, meaning this macro may be difficult to
|
||||||
/// use in some situations.
|
/// use in some situations.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(concat_idents)]
|
/// #![feature(concat_idents)]
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// fn foobar() -> int { 23 }
|
/// fn foobar() -> u32 { 23 }
|
||||||
///
|
///
|
||||||
/// let f = concat_idents!(foo, bar);
|
/// let f = concat_idents!(foo, bar);
|
||||||
/// println!("{}", f());
|
/// println!("{}", f());
|
||||||
|
@ -11,14 +11,18 @@
|
|||||||
//! A type representing values that may be computed concurrently and operations
|
//! A type representing values that may be computed concurrently and operations
|
||||||
//! for working with them.
|
//! for working with them.
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```
|
||||||
//! use std::sync::Future;
|
//! use std::sync::Future;
|
||||||
//! # fn fib(n: uint) -> uint {42};
|
//!
|
||||||
//! # fn make_a_sandwich() {};
|
//! // a fake, for now
|
||||||
//! let mut delayed_fib = Future::spawn(move|| { fib(5000) });
|
//! fn fib(n: u32) -> u32 { 42 };
|
||||||
//! make_a_sandwich();
|
//!
|
||||||
|
//! let mut delayed_fib = Future::spawn(move || fib(5000));
|
||||||
|
//!
|
||||||
|
//! // do stuff...
|
||||||
|
//!
|
||||||
//! println!("fib(5000) = {}", delayed_fib.get())
|
//! println!("fib(5000) = {}", delayed_fib.get())
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ extern crate serialize;
|
|||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|
||||||
extern crate "serialize" as rustc_serialize; // used by deriving
|
extern crate "serialize" as rustc_serialize; // used by deriving
|
||||||
|
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("{}", 1.0 as *libc::FILE); // Can't cast float to foreign.
|
println!("{:?}", 1.0 as *const libc::FILE); // Can't cast float to foreign.
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user