Auto merge of #37755 - polo-language:doc-punct, r=GuillaumeGomez
Improved punctuation, capitalization, and sentence structure of code snippet comments r? @GuillaumeGomez
This commit is contained in:
commit
766f6e4782
41 changed files with 184 additions and 183 deletions
|
@ -11,7 +11,7 @@ this:
|
||||||
trait Graph<N, E> {
|
trait Graph<N, E> {
|
||||||
fn has_edge(&self, &N, &N) -> bool;
|
fn has_edge(&self, &N, &N) -> bool;
|
||||||
fn edges(&self, &N) -> Vec<E>;
|
fn edges(&self, &N) -> Vec<E>;
|
||||||
// etc
|
// Etc.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ trait Graph {
|
||||||
|
|
||||||
fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||||
fn edges(&self, &Self::N) -> Vec<Self::E>;
|
fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||||
// etc
|
// Etc.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ computation entirely. This could be done for the example above by adjusting the
|
||||||
# struct X;
|
# struct X;
|
||||||
# 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`).
|
||||||
(0..1000).fold(0, |old, new| old ^ new)
|
(0..1000).fold(0, |old, new| old ^ new)
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
|
@ -38,7 +38,7 @@ so as to avoid copying a large data structure. For example:
|
||||||
struct BigStruct {
|
struct BigStruct {
|
||||||
one: i32,
|
one: i32,
|
||||||
two: i32,
|
two: i32,
|
||||||
// etc
|
// Etc.
|
||||||
one_hundred: i32,
|
one_hundred: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ This is an antipattern in Rust. Instead, write this:
|
||||||
struct BigStruct {
|
struct BigStruct {
|
||||||
one: i32,
|
one: i32,
|
||||||
two: i32,
|
two: i32,
|
||||||
// etc
|
// Etc.
|
||||||
one_hundred: i32,
|
one_hundred: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ from integers, and to cast between pointers to different types subject to
|
||||||
some constraints. It is only unsafe to dereference the pointer:
|
some constraints. It is only unsafe to dereference the pointer:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let a = 300 as *const char; // a pointer to location 300
|
let a = 300 as *const char; // `a` is a pointer to location 300.
|
||||||
let b = a as u32;
|
let b = a as u32;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -135,14 +135,14 @@ cast four bytes into a `u32`:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
let a = [0u8, 0u8, 0u8, 0u8];
|
let a = [0u8, 0u8, 0u8, 0u8];
|
||||||
|
|
||||||
let b = a as u32; // four u8s makes a u32
|
let b = a as u32; // Four u8s makes a u32.
|
||||||
```
|
```
|
||||||
|
|
||||||
This errors with:
|
This errors with:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
error: non-scalar cast: `[u8; 4]` as `u32`
|
error: non-scalar cast: `[u8; 4]` as `u32`
|
||||||
let b = a as u32; // four u8s makes a u32
|
let b = a as u32; // Four u8s makes a u32.
|
||||||
^~~~~~~~
|
^~~~~~~~
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ fn main() {
|
||||||
let a = [0u8, 1u8, 0u8, 0u8];
|
let a = [0u8, 1u8, 0u8, 0u8];
|
||||||
let b = mem::transmute::<[u8; 4], u32>(a);
|
let b = mem::transmute::<[u8; 4], u32>(a);
|
||||||
println!("{}", b); // 256
|
println!("{}", b); // 256
|
||||||
// or, more concisely:
|
// Or, more concisely:
|
||||||
let c: u32 = mem::transmute(a);
|
let c: u32 = mem::transmute(a);
|
||||||
println!("{}", c); // 256
|
println!("{}", c); // 256
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ the following:
|
||||||
```rust
|
```rust
|
||||||
let x = Box::new(1);
|
let x = Box::new(1);
|
||||||
let y = x;
|
let y = x;
|
||||||
// x no longer accessible here
|
// `x` is no longer accessible here.
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the
|
Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the
|
||||||
|
@ -291,9 +291,9 @@ the inner data (mutably), and the lock will be released when the guard goes out
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
{
|
{
|
||||||
let guard = mutex.lock();
|
let guard = mutex.lock();
|
||||||
// guard dereferences mutably to the inner type
|
// `guard` dereferences mutably to the inner type.
|
||||||
*guard += 1;
|
*guard += 1;
|
||||||
} // lock released when destructor runs
|
} // Lock is released when destructor runs.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ let mut num = 5;
|
||||||
{
|
{
|
||||||
let plus_num = |x: i32| x + num;
|
let plus_num = |x: i32| x + num;
|
||||||
|
|
||||||
} // plus_num goes out of scope, borrow of num ends
|
} // `plus_num` goes out of scope; borrow of `num` ends.
|
||||||
|
|
||||||
let y = &mut num;
|
let y = &mut num;
|
||||||
```
|
```
|
||||||
|
|
|
@ -10,7 +10,7 @@ and *doc comments*.
|
||||||
```rust
|
```rust
|
||||||
// Line comments are anything after ‘//’ and extend to the end of the line.
|
// Line comments are anything after ‘//’ and extend to the end of the line.
|
||||||
|
|
||||||
let x = 5; // this is also a line comment.
|
let x = 5; // This is also a line comment.
|
||||||
|
|
||||||
// If you have a long explanation for something, you can put line comments next
|
// If you have a long explanation for something, you can put line comments next
|
||||||
// to each other. Put a space between the // and your comment so that it’s
|
// to each other. Put a space between the // and your comment so that it’s
|
||||||
|
|
|
@ -48,7 +48,7 @@ extern crate rustc_plugin;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax::tokenstream::TokenTree;
|
use syntax::tokenstream::TokenTree;
|
||||||
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
|
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
|
||||||
use syntax::ext::build::AstBuilder; // trait for expr_usize
|
use syntax::ext::build::AstBuilder; // A trait for expr_usize.
|
||||||
use syntax::ext::quote::rt::Span;
|
use syntax::ext::quote::rt::Span;
|
||||||
use rustc_plugin::Registry;
|
use rustc_plugin::Registry;
|
||||||
|
|
||||||
|
|
|
@ -213,10 +213,10 @@ fn main() {
|
||||||
let mut data = Rc::new(vec![1, 2, 3]);
|
let mut data = Rc::new(vec![1, 2, 3]);
|
||||||
|
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
// create a new owned reference
|
// Create a new owned reference:
|
||||||
let data_ref = data.clone();
|
let data_ref = data.clone();
|
||||||
|
|
||||||
// use it in a thread
|
// Use it in a thread:
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
data_ref[0] += i;
|
data_ref[0] += i;
|
||||||
});
|
});
|
||||||
|
@ -390,8 +390,8 @@ use std::sync::mpsc;
|
||||||
fn main() {
|
fn main() {
|
||||||
let data = Arc::new(Mutex::new(0));
|
let data = Arc::new(Mutex::new(0));
|
||||||
|
|
||||||
// `tx` is the "transmitter" or "sender"
|
// `tx` is the "transmitter" or "sender".
|
||||||
// `rx` is the "receiver"
|
// `rx` is the "receiver".
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
|
|
|
@ -126,7 +126,7 @@ Instead of declaring a module like this:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
mod english {
|
mod english {
|
||||||
// contents of our module go here
|
// Contents of our module go here.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ which allocator is in use is done simply by linking to the desired allocator:
|
||||||
extern crate alloc_system;
|
extern crate alloc_system;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = Box::new(4); // allocates from the system allocator
|
let a = Box::new(4); // Allocates from the system allocator.
|
||||||
println!("{}", a);
|
println!("{}", a);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -57,7 +57,7 @@ uses jemalloc by default one would write:
|
||||||
extern crate alloc_jemalloc;
|
extern crate alloc_jemalloc;
|
||||||
|
|
||||||
pub fn foo() {
|
pub fn foo() {
|
||||||
let a = Box::new(4); // allocates from jemalloc
|
let a = Box::new(4); // Allocates from jemalloc.
|
||||||
println!("{}", a);
|
println!("{}", a);
|
||||||
}
|
}
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
|
@ -72,11 +72,11 @@ crate which implements the allocator API (e.g. the same as `alloc_system` or
|
||||||
annotated version of `alloc_system`
|
annotated version of `alloc_system`
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
# // only needed for rustdoc --test down below
|
# // Only needed for rustdoc --test down below.
|
||||||
# #![feature(lang_items)]
|
# #![feature(lang_items)]
|
||||||
// The compiler needs to be instructed that this crate is an allocator in order
|
// The compiler needs to be instructed that this crate is an allocator in order
|
||||||
// to realize that when this is linked in another allocator like jemalloc should
|
// to realize that when this is linked in another allocator like jemalloc should
|
||||||
// not be linked in
|
// not be linked in.
|
||||||
#![feature(allocator)]
|
#![feature(allocator)]
|
||||||
#![allocator]
|
#![allocator]
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ annotated version of `alloc_system`
|
||||||
// however, can use all of libcore.
|
// however, can use all of libcore.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
// Let's give a unique name to our custom allocator
|
// Let's give a unique name to our custom allocator:
|
||||||
#![crate_name = "my_allocator"]
|
#![crate_name = "my_allocator"]
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
|
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
|
||||||
_size: usize, _align: usize) -> usize {
|
_size: usize, _align: usize) -> usize {
|
||||||
old_size // this api is not supported by libc
|
old_size // This api is not supported by libc.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -134,7 +134,7 @@ pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
|
|
||||||
# // only needed to get rustdoc to test this
|
# // Only needed to get rustdoc to test this:
|
||||||
# fn main() {}
|
# fn main() {}
|
||||||
# #[lang = "panic_fmt"] fn panic_fmt() {}
|
# #[lang = "panic_fmt"] fn panic_fmt() {}
|
||||||
# #[lang = "eh_personality"] fn eh_personality() {}
|
# #[lang = "eh_personality"] fn eh_personality() {}
|
||||||
|
@ -149,7 +149,7 @@ After we compile this crate, it can be used as follows:
|
||||||
extern crate my_allocator;
|
extern crate my_allocator;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = Box::new(8); // allocates memory via our custom allocator crate
|
let a = Box::new(8); // Allocates memory via our custom allocator crate.
|
||||||
println!("{}", a);
|
println!("{}", a);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -33,13 +33,13 @@ automatically coerce to a `&T`. Here’s an example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(s: &str) {
|
fn foo(s: &str) {
|
||||||
// borrow a string for a second
|
// Borrow a string for a second.
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements Deref<Target=str>
|
// String implements Deref<Target=str>.
|
||||||
let owned = "Hello".to_string();
|
let owned = "Hello".to_string();
|
||||||
|
|
||||||
// therefore, this works:
|
// Therefore, this works:
|
||||||
foo(&owned);
|
foo(&owned);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -55,14 +55,14 @@ type implements `Deref<Target=T>`, so this works:
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn foo(s: &str) {
|
fn foo(s: &str) {
|
||||||
// borrow a string for a second
|
// Borrow a string for a second.
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements Deref<Target=str>
|
// String implements Deref<Target=str>.
|
||||||
let owned = "Hello".to_string();
|
let owned = "Hello".to_string();
|
||||||
let counted = Rc::new(owned);
|
let counted = Rc::new(owned);
|
||||||
|
|
||||||
// therefore, this works:
|
// Therefore, this works:
|
||||||
foo(&counted);
|
foo(&counted);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -76,10 +76,10 @@ Another very common implementation provided by the standard library is:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(s: &[i32]) {
|
fn foo(s: &[i32]) {
|
||||||
// borrow a slice for a second
|
// Borrow a slice for a second.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vec<T> implements Deref<Target=[T]>
|
// Vec<T> implements Deref<Target=[T]>.
|
||||||
let owned = vec![1, 2, 3];
|
let owned = vec![1, 2, 3];
|
||||||
|
|
||||||
foo(&owned);
|
foo(&owned);
|
||||||
|
|
|
@ -28,7 +28,7 @@ code. You can use documentation comments for this purpose:
|
||||||
/// let five = Rc::new(5);
|
/// let five = Rc::new(5);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new(value: T) -> Rc<T> {
|
pub fn new(value: T) -> Rc<T> {
|
||||||
// implementation goes here
|
// Implementation goes here.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -483,7 +483,7 @@ you have a module in `foo.rs`, you'll often open its code and see this:
|
||||||
```rust
|
```rust
|
||||||
//! A module for using `foo`s.
|
//! A module for using `foo`s.
|
||||||
//!
|
//!
|
||||||
//! The `foo` module contains a lot of useful functionality blah blah blah
|
//! The `foo` module contains a lot of useful functionality blah blah blah...
|
||||||
```
|
```
|
||||||
|
|
||||||
### Crate documentation
|
### Crate documentation
|
||||||
|
|
|
@ -18,9 +18,9 @@ impl Drop for HasDrop {
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = HasDrop;
|
let x = HasDrop;
|
||||||
|
|
||||||
// do stuff
|
// Do stuff.
|
||||||
|
|
||||||
} // x goes out of scope here
|
} // `x` goes out of scope here.
|
||||||
```
|
```
|
||||||
|
|
||||||
When `x` goes out of scope at the end of `main()`, the code for `Drop` will
|
When `x` goes out of scope at the end of `main()`, the code for `Drop` will
|
||||||
|
|
|
@ -51,7 +51,7 @@ possible variants:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn process_color_change(msg: Message) {
|
fn process_color_change(msg: Message) {
|
||||||
let Message::ChangeColor(r, g, b) = msg; // compile-time error
|
let Message::ChangeColor(r, g, b) = msg; // This causes a compile-time error.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ and in most cases, the entire program aborts.) Here's an example:
|
||||||
|
|
||||||
```rust,should_panic
|
```rust,should_panic
|
||||||
// Guess a number between 1 and 10.
|
// Guess a number between 1 and 10.
|
||||||
// If it matches the number we had in mind, return true. Else, return false.
|
// If it matches the number we had in mind, return `true`. Else, return `false`.
|
||||||
fn guess(n: i32) -> bool {
|
fn guess(n: i32) -> bool {
|
||||||
if n < 1 || n > 10 {
|
if n < 1 || n > 10 {
|
||||||
panic!("Invalid number: {}", n);
|
panic!("Invalid number: {}", n);
|
||||||
|
@ -350,7 +350,7 @@ fn file_path_ext_explicit(file_path: &str) -> Option<&str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_name(file_path: &str) -> Option<&str> {
|
fn file_name(file_path: &str) -> Option<&str> {
|
||||||
// implementation elided
|
// Implementation elided.
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -360,7 +360,7 @@ analysis, but its type doesn't quite fit...
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn file_path_ext(file_path: &str) -> Option<&str> {
|
fn file_path_ext(file_path: &str) -> Option<&str> {
|
||||||
file_name(file_path).map(|x| extension(x)) //Compilation error
|
file_name(file_path).map(|x| extension(x)) // This causes a compilation error.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1235,11 +1235,11 @@ use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
// We have to jump through some hoops to actually get error values.
|
// We have to jump through some hoops to actually get error values:
|
||||||
let io_err: io::Error = io::Error::last_os_error();
|
let io_err: io::Error = io::Error::last_os_error();
|
||||||
let parse_err: num::ParseIntError = "not a number".parse::<i32>().unwrap_err();
|
let parse_err: num::ParseIntError = "not a number".parse::<i32>().unwrap_err();
|
||||||
|
|
||||||
// OK, here are the conversions.
|
// OK, here are the conversions:
|
||||||
let err1: Box<Error> = From::from(io_err);
|
let err1: Box<Error> = From::from(io_err);
|
||||||
let err2: Box<Error> = From::from(parse_err);
|
let err2: Box<Error> = From::from(parse_err);
|
||||||
```
|
```
|
||||||
|
@ -1609,7 +1609,7 @@ fn main() {
|
||||||
let data_path = &matches.free[0];
|
let data_path = &matches.free[0];
|
||||||
let city: &str = &matches.free[1];
|
let city: &str = &matches.free[1];
|
||||||
|
|
||||||
// Do stuff with information
|
// Do stuff with information.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1747,7 +1747,7 @@ simply ignoring that row.
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
struct Row {
|
struct Row {
|
||||||
// unchanged
|
// This struct remains unchanged.
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PopulationCount {
|
struct PopulationCount {
|
||||||
|
@ -1769,7 +1769,7 @@ fn search<P: AsRef<Path>>(file_path: P, city: &str) -> Vec<PopulationCount> {
|
||||||
for row in rdr.decode::<Row>() {
|
for row in rdr.decode::<Row>() {
|
||||||
let row = row.unwrap();
|
let row = row.unwrap();
|
||||||
match row.population {
|
match row.population {
|
||||||
None => { } // skip it
|
None => { } // Skip it.
|
||||||
Some(count) => if row.city == city {
|
Some(count) => if row.city == city {
|
||||||
found.push(PopulationCount {
|
found.push(PopulationCount {
|
||||||
city: row.city,
|
city: row.city,
|
||||||
|
@ -1825,7 +1825,7 @@ Let's try it:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
// The rest of the code before this is unchanged
|
// The rest of the code before this is unchanged.
|
||||||
|
|
||||||
fn search<P: AsRef<Path>>
|
fn search<P: AsRef<Path>>
|
||||||
(file_path: P, city: &str)
|
(file_path: P, city: &str)
|
||||||
|
@ -1836,7 +1836,7 @@ fn search<P: AsRef<Path>>
|
||||||
for row in rdr.decode::<Row>() {
|
for row in rdr.decode::<Row>() {
|
||||||
let row = try!(row);
|
let row = try!(row);
|
||||||
match row.population {
|
match row.population {
|
||||||
None => { } // skip it
|
None => { } // Skip it.
|
||||||
Some(count) => if row.city == city {
|
Some(count) => if row.city == city {
|
||||||
found.push(PopulationCount {
|
found.push(PopulationCount {
|
||||||
city: row.city,
|
city: row.city,
|
||||||
|
@ -1957,7 +1957,7 @@ that it is generic on some type parameter `R` that satisfies
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
// The rest of the code before this is unchanged
|
// The rest of the code before this is unchanged.
|
||||||
|
|
||||||
fn search<P: AsRef<Path>>
|
fn search<P: AsRef<Path>>
|
||||||
(file_path: &Option<P>, city: &str)
|
(file_path: &Option<P>, city: &str)
|
||||||
|
@ -2070,7 +2070,7 @@ fn search<P: AsRef<Path>>
|
||||||
for row in rdr.decode::<Row>() {
|
for row in rdr.decode::<Row>() {
|
||||||
let row = try!(row);
|
let row = try!(row);
|
||||||
match row.population {
|
match row.population {
|
||||||
None => { } // skip it
|
None => { } // Skip it.
|
||||||
Some(count) => if row.city == city {
|
Some(count) => if row.city == city {
|
||||||
found.push(PopulationCount {
|
found.push(PopulationCount {
|
||||||
city: row.city,
|
city: row.city,
|
||||||
|
|
|
@ -277,7 +277,7 @@ extern {
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
register_callback(callback);
|
register_callback(callback);
|
||||||
trigger_callback(); // Triggers the callback
|
trigger_callback(); // Triggers the callback.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -294,7 +294,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.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -320,13 +320,13 @@ Rust code:
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct RustObject {
|
struct RustObject {
|
||||||
a: i32,
|
a: i32,
|
||||||
// other members
|
// Other members...
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn callback(target: *mut RustObject, a: i32) {
|
extern "C" fn callback(target: *mut RustObject, a: i32) {
|
||||||
println!("I'm called from C with value {0}", a);
|
println!("I'm called from C with value {0}", a);
|
||||||
unsafe {
|
unsafe {
|
||||||
// Update the value in RustObject with the value received from the callback
|
// Update the value in RustObject with the value received from the callback:
|
||||||
(*target).a = a;
|
(*target).a = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,7 +339,7 @@ extern {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Create the object that will be referenced in the callback
|
// Create the object that will be referenced in the callback:
|
||||||
let mut rust_object = Box::new(RustObject { a: 5 });
|
let mut rust_object = Box::new(RustObject { a: 5 });
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -363,7 +363,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.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -606,7 +606,7 @@ use libc::c_int;
|
||||||
|
|
||||||
# #[cfg(hidden)]
|
# #[cfg(hidden)]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/// Register the callback.
|
/// Registers the callback.
|
||||||
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
|
fn register(cb: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>, c_int) -> c_int>);
|
||||||
}
|
}
|
||||||
# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
|
# unsafe fn register(_: Option<extern "C" fn(Option<extern "C" fn(c_int) -> c_int>,
|
||||||
|
|
|
@ -135,7 +135,7 @@ In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||||
following will produce a compile-time error:
|
following will produce a compile-time error:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
let x = (let y = 5); // expected identifier, found keyword `let`
|
let x = (let y = 5); // Expected identifier, found keyword `let`.
|
||||||
```
|
```
|
||||||
|
|
||||||
The compiler is telling us here that it was expecting to see the beginning of
|
The compiler is telling us here that it was expecting to see the beginning of
|
||||||
|
@ -151,7 +151,7 @@ other returned value would be too surprising:
|
||||||
```rust
|
```rust
|
||||||
let mut y = 5;
|
let mut y = 5;
|
||||||
|
|
||||||
let x = (y = 6); // x has the value `()`, not `6`
|
let x = (y = 6); // `x` has the value `()`, not `6`.
|
||||||
```
|
```
|
||||||
|
|
||||||
The second kind of statement in Rust is the *expression statement*. Its
|
The second kind of statement in Rust is the *expression statement*. Its
|
||||||
|
@ -183,7 +183,7 @@ But what about early returns? Rust does have a keyword for that, `return`:
|
||||||
fn foo(x: i32) -> i32 {
|
fn foo(x: i32) -> i32 {
|
||||||
return x;
|
return x;
|
||||||
|
|
||||||
// we never run this code!
|
// We never run this code!
|
||||||
x + 1
|
x + 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -307,10 +307,10 @@ fn plus_one(i: i32) -> i32 {
|
||||||
i + 1
|
i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// without type inference
|
// Without type inference:
|
||||||
let f: fn(i32) -> i32 = plus_one;
|
let f: fn(i32) -> i32 = plus_one;
|
||||||
|
|
||||||
// with type inference
|
// With type inference:
|
||||||
let f = plus_one;
|
let f = plus_one;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ We can write functions that take generic types with a similar syntax:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn takes_anything<T>(x: T) {
|
fn takes_anything<T>(x: T) {
|
||||||
// do something with x
|
// Do something with `x`.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -158,8 +158,8 @@ take a name on the left hand side of the assignment, it actually accepts a
|
||||||
to use for now:
|
to use for now:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let foo = 5; // immutable.
|
let foo = 5; // `foo` is immutable.
|
||||||
let mut bar = 5; // mutable
|
let mut bar = 5; // `bar` is mutable.
|
||||||
```
|
```
|
||||||
|
|
||||||
[immutable]: mutability.html
|
[immutable]: mutability.html
|
||||||
|
|
|
@ -34,7 +34,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// other platforms
|
// Other platforms:
|
||||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
fn foo() { /* ... */ }
|
fn foo() { /* ... */ }
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ stay valid.
|
||||||
# #![feature(asm)]
|
# #![feature(asm)]
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
# fn main() { unsafe {
|
# fn main() { unsafe {
|
||||||
// Put the value 0x200 in eax
|
// Put the value 0x200 in eax:
|
||||||
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
||||||
# } }
|
# } }
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub struct Box<T>(*mut T);
|
||||||
unsafe fn allocate(size: usize, _align: usize) -> *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
|
// Check if `malloc` failed:
|
||||||
if p as usize == 0 {
|
if p as usize == 0 {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,13 +54,13 @@ dangling pointer or ‘use after free’, when the resource is memory. A small
|
||||||
example of such a situation would be:
|
example of such a situation would be:
|
||||||
|
|
||||||
```rust,compile_fail
|
```rust,compile_fail
|
||||||
let r; // Introduce reference: r
|
let r; // Introduce reference: `r`.
|
||||||
{
|
{
|
||||||
let i = 1; // Introduce scoped value: i
|
let i = 1; // Introduce scoped value: `i`.
|
||||||
r = &i; // Store reference of i in r
|
r = &i; // Store reference of `i` in `r`.
|
||||||
} // i goes out of scope and is dropped.
|
} // `i` goes out of scope and is dropped.
|
||||||
|
|
||||||
println!("{}", r); // r still refers to i
|
println!("{}", r); // `r` still refers to `i`.
|
||||||
```
|
```
|
||||||
|
|
||||||
To fix this, we have to make sure that step four never happens after step
|
To fix this, we have to make sure that step four never happens after step
|
||||||
|
@ -81,9 +81,9 @@ let lang = "en";
|
||||||
|
|
||||||
let v;
|
let v;
|
||||||
{
|
{
|
||||||
let p = format!("lang:{}=", lang); // -+ p goes into scope
|
let p = format!("lang:{}=", lang); // -+ `p` comes into scope.
|
||||||
v = skip_prefix(line, p.as_str()); // |
|
v = skip_prefix(line, p.as_str()); // |
|
||||||
} // -+ p goes out of scope
|
} // -+ `p` goes out of scope.
|
||||||
println!("{}", v);
|
println!("{}", v);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ struct Foo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
|
let y = &5; // This is the same as `let _y = 5; let y = &_y;`.
|
||||||
let f = Foo { x: y };
|
let f = Foo { x: y };
|
||||||
|
|
||||||
println!("{}", f.x);
|
println!("{}", f.x);
|
||||||
|
@ -233,7 +233,7 @@ impl<'a> Foo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let y = &5; // this is the same as `let _y = 5; let y = &_y;`
|
let y = &5; // This is the same as `let _y = 5; let y = &_y;`.
|
||||||
let f = Foo { x: y };
|
let f = Foo { x: y };
|
||||||
|
|
||||||
println!("x is: {}", f.x());
|
println!("x is: {}", f.x());
|
||||||
|
@ -274,11 +274,11 @@ valid for. For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn main() {
|
fn main() {
|
||||||
let y = &5; // -+ y goes into scope
|
let y = &5; // -+ `y` comes into scope.
|
||||||
// |
|
// |
|
||||||
// stuff // |
|
// Stuff... // |
|
||||||
// |
|
// |
|
||||||
} // -+ y goes out of scope
|
} // -+ `y` goes out of scope.
|
||||||
```
|
```
|
||||||
|
|
||||||
Adding in our `Foo`:
|
Adding in our `Foo`:
|
||||||
|
@ -289,11 +289,12 @@ struct Foo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let y = &5; // -+ y goes into scope
|
let y = &5; // -+ `y` comes into scope.
|
||||||
let f = Foo { x: y }; // -+ f goes into scope
|
let f = Foo { x: y }; // -+ `f` comes into scope.
|
||||||
// stuff // |
|
|
||||||
// |
|
// |
|
||||||
} // -+ f and y go out of scope
|
// Stuff... // |
|
||||||
|
// |
|
||||||
|
} // -+ `f` and `y` go out of scope.
|
||||||
```
|
```
|
||||||
|
|
||||||
Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
|
Our `f` lives within the scope of `y`, so everything works. What if it didn’t?
|
||||||
|
@ -305,16 +306,16 @@ struct Foo<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x; // -+ x goes into scope
|
let x; // -+ `x` comes into scope.
|
||||||
// |
|
// |
|
||||||
{ // |
|
{ // |
|
||||||
let y = &5; // ---+ y goes into scope
|
let y = &5; // ---+ `y` comes into scope.
|
||||||
let f = Foo { x: y }; // ---+ f goes into scope
|
let f = Foo { x: y }; // ---+ `f` comes into scope.
|
||||||
x = &f.x; // | | error here
|
x = &f.x; // | | This causes an error.
|
||||||
} // ---+ f and y go out of scope
|
} // ---+ `f` and y go out of scope.
|
||||||
// |
|
// |
|
||||||
println!("{}", x); // |
|
println!("{}", x); // |
|
||||||
} // -+ x goes out of scope
|
} // -+ `x` goes out of scope.
|
||||||
```
|
```
|
||||||
|
|
||||||
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
|
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
|
||||||
|
|
|
@ -202,8 +202,8 @@ of the outer loops, you can use labels to specify which loop the `break` or
|
||||||
```rust
|
```rust
|
||||||
'outer: for x in 0..10 {
|
'outer: for x in 0..10 {
|
||||||
'inner: for y in 0..10 {
|
'inner: for y in 0..10 {
|
||||||
if x % 2 == 0 { continue 'outer; } // continues the loop over x
|
if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`.
|
||||||
if y % 2 == 0 { continue 'inner; } // continues the loop over y
|
if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`.
|
||||||
println!("x: {}, y: {}", x, y);
|
println!("x: {}, y: {}", x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,33 +533,33 @@ An example:
|
||||||
```rust
|
```rust
|
||||||
macro_rules! m1 { () => (()) }
|
macro_rules! m1 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1
|
// Visible here: `m1`.
|
||||||
|
|
||||||
mod foo {
|
mod foo {
|
||||||
// visible here: m1
|
// Visible here: `m1`.
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! m2 { () => (()) }
|
macro_rules! m2 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m2
|
// Visible here: `m1`, `m2`.
|
||||||
}
|
}
|
||||||
|
|
||||||
// visible here: m1
|
// Visible here: `m1`.
|
||||||
|
|
||||||
macro_rules! m3 { () => (()) }
|
macro_rules! m3 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m3
|
// Visible here: `m1`, `m3`.
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod bar {
|
mod bar {
|
||||||
// visible here: m1, m3
|
// Visible here: `m1`, `m3`.
|
||||||
|
|
||||||
macro_rules! m4 { () => (()) }
|
macro_rules! m4 { () => (()) }
|
||||||
|
|
||||||
// visible here: m1, m3, m4
|
// Visible here: `m1`, `m3`, `m4`.
|
||||||
}
|
}
|
||||||
|
|
||||||
// visible here: m1, m3, m4
|
// Visible here: `m1`, `m3`, `m4`.
|
||||||
# fn main() { }
|
# fn main() { }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -644,7 +644,7 @@ macro_rules! bct {
|
||||||
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
(1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
|
||||||
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
=> (bct!($($ps),*, 1, $p ; $($ds),*));
|
||||||
|
|
||||||
// halt on empty data string
|
// Halt on empty data string:
|
||||||
( $($ps:tt),* ; )
|
( $($ps:tt),* ; )
|
||||||
=> (());
|
=> (());
|
||||||
}
|
}
|
||||||
|
@ -694,7 +694,7 @@ Like this:
|
||||||
assert!(true);
|
assert!(true);
|
||||||
assert_eq!(5, 3 + 2);
|
assert_eq!(5, 3 + 2);
|
||||||
|
|
||||||
// nope :(
|
// Nope :(
|
||||||
|
|
||||||
assert!(5 < 3);
|
assert!(5 < 3);
|
||||||
assert_eq!(5, 3);
|
assert_eq!(5, 3);
|
||||||
|
|
|
@ -6,7 +6,7 @@ status:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
let x = 5;
|
let x = 5;
|
||||||
x = 6; // error!
|
x = 6; // Error!
|
||||||
```
|
```
|
||||||
|
|
||||||
We can introduce mutability with the `mut` keyword:
|
We can introduce mutability with the `mut` keyword:
|
||||||
|
@ -14,7 +14,7 @@ We can introduce mutability with the `mut` keyword:
|
||||||
```rust
|
```rust
|
||||||
let mut x = 5;
|
let mut x = 5;
|
||||||
|
|
||||||
x = 6; // no problem!
|
x = 6; // No problem!
|
||||||
```
|
```
|
||||||
|
|
||||||
This is a mutable [variable binding][vb]. When a binding is mutable, it means
|
This is a mutable [variable binding][vb]. When a binding is mutable, it means
|
||||||
|
@ -136,7 +136,7 @@ some fields mutable and some immutable:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
struct Point {
|
struct Point {
|
||||||
x: i32,
|
x: i32,
|
||||||
mut y: i32, // nope
|
mut y: i32, // Nope.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ a.x = 10;
|
||||||
|
|
||||||
let b = Point { x: 5, y: 6};
|
let b = Point { x: 5, y: 6};
|
||||||
|
|
||||||
b.x = 10; // error: cannot assign to immutable field `b.x`
|
b.x = 10; // Error: cannot assign to immutable field `b.x`.
|
||||||
```
|
```
|
||||||
|
|
||||||
[struct]: structs.html
|
[struct]: structs.html
|
||||||
|
|
|
@ -41,10 +41,10 @@ in the same format as C:
|
||||||
#![feature(start)]
|
#![feature(start)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
// Pull in the system libc library for what crt0.o likely requires
|
// Pull in the system libc library for what crt0.o likely requires.
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// Entry point for this program
|
// Entry point for this program.
|
||||||
#[start]
|
#[start]
|
||||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
0
|
0
|
||||||
|
@ -84,10 +84,10 @@ compiler's name mangling too:
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
// Pull in the system libc library for what crt0.o likely requires
|
// Pull in the system libc library for what crt0.o likely requires.
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// Entry point for this program
|
// Entry point for this program.
|
||||||
#[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: i32, _argv: *const *const u8) -> i32 {
|
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||||
0
|
0
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Add<i32> for Point {
|
||||||
type Output = f64;
|
type Output = f64;
|
||||||
|
|
||||||
fn add(self, rhs: i32) -> f64 {
|
fn add(self, rhs: i32) -> f64 {
|
||||||
// add an i32 to a Point and get an f64
|
// Add an i32 to a Point and get an f64.
|
||||||
# 1.0
|
# 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ try to use something after we’ve passed it as an argument:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn take(v: Vec<i32>) {
|
fn take(v: Vec<i32>) {
|
||||||
// what happens here isn’t important.
|
// What happens here isn’t important.
|
||||||
}
|
}
|
||||||
|
|
||||||
let v = vec![1, 2, 3];
|
let v = vec![1, 2, 3];
|
||||||
|
@ -264,9 +264,9 @@ Of course, if we had to hand ownership back with every function we wrote:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(v: Vec<i32>) -> Vec<i32> {
|
fn foo(v: Vec<i32>) -> Vec<i32> {
|
||||||
// do stuff with v
|
// Do stuff with `v`.
|
||||||
|
|
||||||
// hand back ownership
|
// Hand back ownership.
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -275,9 +275,9 @@ This would get very tedious. It gets worse the more things we want to take owner
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
||||||
// do stuff with v1 and v2
|
// Do stuff with `v1` and `v2`.
|
||||||
|
|
||||||
// hand back ownership, and the result of our function
|
// Hand back ownership, and the result of our function.
|
||||||
(v1, v2, 42)
|
(v1, v2, 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ ignore parts of a larger structure:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn coordinate() -> (i32, i32, i32) {
|
fn coordinate() -> (i32, i32, i32) {
|
||||||
// generate and return some sort of triple tuple
|
// Generate and return some sort of triple tuple.
|
||||||
# (1, 2, 3)
|
# (1, 2, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ let tuple: (u32, String) = (5, String::from("five"));
|
||||||
// Here, tuple is moved, because the String moved:
|
// Here, tuple is moved, because the String moved:
|
||||||
let (x, _s) = tuple;
|
let (x, _s) = tuple;
|
||||||
|
|
||||||
// The next line would give "error: use of partially moved value: `tuple`"
|
// The next line would give "error: use of partially moved value: `tuple`".
|
||||||
// println!("Tuple is: {:?}", tuple);
|
// println!("Tuple is: {:?}", tuple);
|
||||||
|
|
||||||
// However,
|
// However,
|
||||||
|
|
|
@ -54,9 +54,9 @@ bigger numbers.
|
||||||
If a number literal has nothing to cause its type to be inferred, it defaults:
|
If a number literal has nothing to cause its type to be inferred, it defaults:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = 42; // x has type i32
|
let x = 42; // `x` has type `i32`.
|
||||||
|
|
||||||
let y = 1.0; // y has type f64
|
let y = 1.0; // `y` has type `f64`.
|
||||||
```
|
```
|
||||||
|
|
||||||
Here’s a list of the different numeric types, with links to their documentation
|
Here’s a list of the different numeric types, with links to their documentation
|
||||||
|
@ -177,8 +177,8 @@ length of the slice:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let a = [0, 1, 2, 3, 4];
|
let a = [0, 1, 2, 3, 4];
|
||||||
let complete = &a[..]; // A slice containing all of the elements in a
|
let complete = &a[..]; // A slice containing all of the elements in `a`.
|
||||||
let middle = &a[1..4]; // A slice of a: only the elements 1, 2, and 3
|
let middle = &a[1..4]; // A slice of `a`: only the elements `1`, `2`, and `3`.
|
||||||
```
|
```
|
||||||
|
|
||||||
Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
||||||
|
@ -264,8 +264,8 @@ You can disambiguate a single-element tuple from a value in parentheses with a
|
||||||
comma:
|
comma:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
(0,); // single-element tuple
|
(0,); // A single-element tuple.
|
||||||
(0); // zero in parentheses
|
(0); // A zero in parentheses.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tuple Indexing
|
## Tuple Indexing
|
||||||
|
|
|
@ -101,11 +101,11 @@ programmer *must* guarantee this.
|
||||||
The recommended method for the conversion is:
|
The recommended method for the conversion is:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// explicit cast
|
// Explicit cast:
|
||||||
let i: u32 = 1;
|
let i: u32 = 1;
|
||||||
let p_imm: *const u32 = &i as *const u32;
|
let p_imm: *const u32 = &i as *const u32;
|
||||||
|
|
||||||
// implicit coercion
|
// Implicit coercion:
|
||||||
let mut m: u32 = 2;
|
let mut m: u32 = 2;
|
||||||
let p_mut: *mut u32 = &mut m;
|
let p_mut: *mut u32 = &mut m;
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,9 @@ like this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
||||||
// do stuff with v1 and v2
|
// Do stuff with `v1` and `v2`.
|
||||||
|
|
||||||
// hand back ownership, and the result of our function
|
// Hand back ownership, and the result of our function.
|
||||||
(v1, v2, 42)
|
(v1, v2, 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,9 +63,9 @@ the first step:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
|
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
|
||||||
// do stuff with v1 and v2
|
// Do stuff with `v1` and `v2`.
|
||||||
|
|
||||||
// return the answer
|
// Return the answer.
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ let v2 = vec![1, 2, 3];
|
||||||
|
|
||||||
let answer = foo(&v1, &v2);
|
let answer = foo(&v1, &v2);
|
||||||
|
|
||||||
// we can use v1 and v2 here!
|
// We can use `v1` and `v2` here!
|
||||||
```
|
```
|
||||||
|
|
||||||
A more concrete example:
|
A more concrete example:
|
||||||
|
@ -88,10 +88,10 @@ fn main() {
|
||||||
// Borrow two vectors and sum them.
|
// Borrow two vectors and sum them.
|
||||||
// This kind of borrowing does not allow mutation through the borrowed reference.
|
// This kind of borrowing does not allow mutation through the borrowed reference.
|
||||||
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
|
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
|
||||||
// do stuff with v1 and v2
|
// Do stuff with `v1` and `v2`.
|
||||||
let s1 = sum_vec(v1);
|
let s1 = sum_vec(v1);
|
||||||
let s2 = sum_vec(v2);
|
let s2 = sum_vec(v2);
|
||||||
// return the answer
|
// Return the answer.
|
||||||
s1 + s2
|
s1 + s2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,12 +248,12 @@ scopes look like this:
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut x = 5;
|
let mut x = 5;
|
||||||
|
|
||||||
let y = &mut x; // -+ &mut borrow of x starts here
|
let y = &mut x; // -+ &mut borrow of `x` starts here.
|
||||||
// |
|
// |
|
||||||
*y += 1; // |
|
*y += 1; // |
|
||||||
// |
|
// |
|
||||||
println!("{}", x); // -+ - try to borrow x here
|
println!("{}", x); // -+ - Try to borrow `x` here.
|
||||||
} // -+ &mut borrow of x ends here
|
} // -+ &mut borrow of `x` ends here.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -265,11 +265,11 @@ So when we add the curly braces:
|
||||||
let mut x = 5;
|
let mut x = 5;
|
||||||
|
|
||||||
{
|
{
|
||||||
let y = &mut x; // -+ &mut borrow starts here
|
let y = &mut x; // -+ &mut borrow starts here.
|
||||||
*y += 1; // |
|
*y += 1; // |
|
||||||
} // -+ ... and ends here
|
} // -+ ... and ends here.
|
||||||
|
|
||||||
println!("{}", x); // <- try to borrow x here
|
println!("{}", x); // <- Try to borrow `x` here.
|
||||||
```
|
```
|
||||||
|
|
||||||
There’s no problem. Our mutable borrow goes out of scope before we create an
|
There’s no problem. Our mutable borrow goes out of scope before we create an
|
||||||
|
|
|
@ -83,10 +83,10 @@ converted using `&*`.
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
|
||||||
TcpStream::connect("192.168.0.1:3000"); // &str parameter
|
TcpStream::connect("192.168.0.1:3000"); // Parameter is of type &str.
|
||||||
|
|
||||||
let addr_string = "192.168.0.1:3000".to_string();
|
let addr_string = "192.168.0.1:3000".to_string();
|
||||||
TcpStream::connect(&*addr_string); // convert addr_string to &str
|
TcpStream::connect(&*addr_string); // Convert `addr_string` to &str.
|
||||||
```
|
```
|
||||||
|
|
||||||
Viewing a `String` as a `&str` is cheap, but converting the `&str` to a
|
Viewing a `String` as a `&str` is cheap, but converting the `&str` to a
|
||||||
|
@ -138,7 +138,7 @@ You can get something similar to an index like this:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# let hachiko = "忠犬ハチ公";
|
# let hachiko = "忠犬ハチ公";
|
||||||
let dog = hachiko.chars().nth(1); // kinda like hachiko[1]
|
let dog = hachiko.chars().nth(1); // Kinda like `hachiko[1]`.
|
||||||
```
|
```
|
||||||
|
|
||||||
This emphasizes that we have to walk from the beginning of the list of `chars`.
|
This emphasizes that we have to walk from the beginning of the list of `chars`.
|
||||||
|
|
|
@ -82,9 +82,9 @@ fn main() {
|
||||||
|
|
||||||
point.x = 5;
|
point.x = 5;
|
||||||
|
|
||||||
let point = point; // now immutable
|
let point = point; // `point` is now immutable.
|
||||||
|
|
||||||
point.y = 6; // this causes an error
|
point.y = 6; // This causes an error.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -234,10 +234,10 @@ rather than positions.
|
||||||
You can define a `struct` with no members at all:
|
You can define a `struct` with no members at all:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
struct Electron {} // use empty braces...
|
struct Electron {} // Use empty braces...
|
||||||
struct Proton; // ...or just a semicolon
|
struct Proton; // ...or just a semicolon.
|
||||||
|
|
||||||
// whether you declared the struct with braces or not, do the same when creating one
|
// Whether you declared the struct with braces or not, do the same when creating one.
|
||||||
let x = Electron {};
|
let x = Electron {};
|
||||||
let y = Proton;
|
let y = Proton;
|
||||||
```
|
```
|
||||||
|
|
|
@ -299,7 +299,7 @@ fn it_works() {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn expensive_test() {
|
fn expensive_test() {
|
||||||
// code that takes an hour to run
|
// Code that takes an hour to run...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -221,8 +221,8 @@ struct FooVtable {
|
||||||
// u8:
|
// u8:
|
||||||
|
|
||||||
fn call_method_on_u8(x: *const ()) -> String {
|
fn call_method_on_u8(x: *const ()) -> String {
|
||||||
// the compiler guarantees that this function is only called
|
// The compiler guarantees that this function is only called
|
||||||
// with `x` pointing to a u8
|
// with `x` pointing to a u8.
|
||||||
let byte: &u8 = unsafe { &*(x as *const u8) };
|
let byte: &u8 = unsafe { &*(x as *const u8) };
|
||||||
|
|
||||||
byte.method()
|
byte.method()
|
||||||
|
@ -233,7 +233,7 @@ static Foo_for_u8_vtable: FooVtable = FooVtable {
|
||||||
size: 1,
|
size: 1,
|
||||||
align: 1,
|
align: 1,
|
||||||
|
|
||||||
// cast to a function pointer
|
// Cast to a function pointer:
|
||||||
method: call_method_on_u8 as fn(*const ()) -> String,
|
method: call_method_on_u8 as fn(*const ()) -> String,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -241,8 +241,8 @@ static Foo_for_u8_vtable: FooVtable = FooVtable {
|
||||||
// String:
|
// String:
|
||||||
|
|
||||||
fn call_method_on_String(x: *const ()) -> String {
|
fn call_method_on_String(x: *const ()) -> String {
|
||||||
// the compiler guarantees that this function is only called
|
// The compiler guarantees that this function is only called
|
||||||
// with `x` pointing to a String
|
// with `x` pointing to a String.
|
||||||
let string: &String = unsafe { &*(x as *const String) };
|
let string: &String = unsafe { &*(x as *const String) };
|
||||||
|
|
||||||
string.method()
|
string.method()
|
||||||
|
@ -250,7 +250,7 @@ fn call_method_on_String(x: *const ()) -> String {
|
||||||
|
|
||||||
static Foo_for_String_vtable: FooVtable = FooVtable {
|
static Foo_for_String_vtable: FooVtable = FooVtable {
|
||||||
destructor: /* compiler magic */,
|
destructor: /* compiler magic */,
|
||||||
// values for a 64-bit computer, halve them for 32-bit ones
|
// Values for a 64-bit computer, halve them for 32-bit ones.
|
||||||
size: 24,
|
size: 24,
|
||||||
align: 8,
|
align: 8,
|
||||||
|
|
||||||
|
@ -278,17 +278,17 @@ let x: u8 = 1;
|
||||||
|
|
||||||
// let b: &Foo = &a;
|
// let b: &Foo = &a;
|
||||||
let b = TraitObject {
|
let b = TraitObject {
|
||||||
// store the data
|
// Store the data:
|
||||||
data: &a,
|
data: &a,
|
||||||
// store the methods
|
// Store the methods:
|
||||||
vtable: &Foo_for_String_vtable
|
vtable: &Foo_for_String_vtable
|
||||||
};
|
};
|
||||||
|
|
||||||
// let y: &Foo = x;
|
// let y: &Foo = x;
|
||||||
let y = TraitObject {
|
let y = TraitObject {
|
||||||
// store the data
|
// Store the data:
|
||||||
data: &x,
|
data: &x,
|
||||||
// store the methods
|
// Store the methods:
|
||||||
vtable: &Foo_for_u8_vtable
|
vtable: &Foo_for_u8_vtable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -270,9 +270,9 @@ won’t have its methods:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||||
let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
|
let buf = b"whatever"; // buf: &[u8; 8], a byte string literal.
|
||||||
let result = f.write(buf);
|
let result = f.write(buf);
|
||||||
# result.unwrap(); // ignore the error
|
# result.unwrap(); // Ignore the error.
|
||||||
```
|
```
|
||||||
|
|
||||||
Here’s the error:
|
Here’s the error:
|
||||||
|
@ -291,7 +291,7 @@ use std::io::Write;
|
||||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||||
let buf = b"whatever";
|
let buf = b"whatever";
|
||||||
let result = f.write(buf);
|
let result = f.write(buf);
|
||||||
# result.unwrap(); // ignore the error
|
# result.unwrap(); // Ignore the error.
|
||||||
```
|
```
|
||||||
|
|
||||||
This will compile without error.
|
This will compile without error.
|
||||||
|
@ -413,14 +413,14 @@ impl ConvertTo<i64> for i32 {
|
||||||
fn convert(&self) -> i64 { *self as i64 }
|
fn convert(&self) -> i64 { *self as i64 }
|
||||||
}
|
}
|
||||||
|
|
||||||
// can be called with T == i32
|
// Can be called with T == i32.
|
||||||
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
|
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
|
||||||
x.convert()
|
x.convert()
|
||||||
}
|
}
|
||||||
|
|
||||||
// can be called with T == i64
|
// Can be called with T == i64.
|
||||||
fn inverse<T>(x: i32) -> T
|
fn inverse<T>(x: i32) -> T
|
||||||
// this is using ConvertTo as if it were "ConvertTo<i64>"
|
// This is using ConvertTo as if it were "ConvertTo<i64>".
|
||||||
where i32: ConvertTo<T> {
|
where i32: ConvertTo<T> {
|
||||||
x.convert()
|
x.convert()
|
||||||
}
|
}
|
||||||
|
@ -470,15 +470,15 @@ impl Foo for OverrideDefault {
|
||||||
|
|
||||||
fn is_invalid(&self) -> bool {
|
fn is_invalid(&self) -> bool {
|
||||||
println!("Called OverrideDefault.is_invalid!");
|
println!("Called OverrideDefault.is_invalid!");
|
||||||
true // overrides the expected value of is_invalid()
|
true // Overrides the expected value of `is_invalid()`.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = UseDefault;
|
let default = UseDefault;
|
||||||
assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid."
|
assert!(!default.is_invalid()); // Prints "Called UseDefault.is_valid."
|
||||||
|
|
||||||
let over = OverrideDefault;
|
let over = OverrideDefault;
|
||||||
assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!"
|
assert!(over.is_invalid()); // Prints "Called OverrideDefault.is_invalid!"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Inheritance
|
# Inheritance
|
||||||
|
|
|
@ -12,7 +12,7 @@ four contexts. The first one is to mark a function as unsafe:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
unsafe fn danger_will_robinson() {
|
unsafe fn danger_will_robinson() {
|
||||||
// scary stuff
|
// Scary stuff...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ The second use of `unsafe` is an unsafe block:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
unsafe {
|
unsafe {
|
||||||
// scary stuff
|
// Scary stuff...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ fn main() {
|
||||||
let y: i32 = 3;
|
let y: i32 = 3;
|
||||||
println!("The value of x is {} and value of y is {}", x, y);
|
println!("The value of x is {} and value of y is {}", x, y);
|
||||||
}
|
}
|
||||||
println!("The value of x is {} and value of y is {}", x, y); // This won't work
|
println!("The value of x is {} and value of y is {}", x, y); // This won't work.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ Instead we get this error:
|
||||||
$ cargo build
|
$ cargo build
|
||||||
Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
|
Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
|
||||||
main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
|
main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
|
||||||
main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work
|
main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work.
|
||||||
^
|
^
|
||||||
note: in expansion of format_args!
|
note: in expansion of format_args!
|
||||||
<std macros>:2:25: 2:56 note: expansion site
|
<std macros>:2:25: 2:56 note: expansion site
|
||||||
|
@ -229,13 +229,13 @@ scope will override the previous binding.
|
||||||
```rust
|
```rust
|
||||||
let x: i32 = 8;
|
let x: i32 = 8;
|
||||||
{
|
{
|
||||||
println!("{}", x); // Prints "8"
|
println!("{}", x); // Prints "8".
|
||||||
let x = 12;
|
let x = 12;
|
||||||
println!("{}", x); // Prints "12"
|
println!("{}", x); // Prints "12".
|
||||||
}
|
}
|
||||||
println!("{}", x); // Prints "8"
|
println!("{}", x); // Prints "8".
|
||||||
let x = 42;
|
let x = 42;
|
||||||
println!("{}", x); // Prints "42"
|
println!("{}", x); // Prints "42".
|
||||||
```
|
```
|
||||||
|
|
||||||
Shadowing and mutable bindings may appear as two sides of the same coin, but
|
Shadowing and mutable bindings may appear as two sides of the same coin, but
|
||||||
|
@ -249,8 +249,8 @@ by any means.
|
||||||
```rust
|
```rust
|
||||||
let mut x: i32 = 1;
|
let mut x: i32 = 1;
|
||||||
x = 7;
|
x = 7;
|
||||||
let x = x; // x is now immutable and is bound to 7
|
let x = x; // `x` is now immutable and is bound to `7`.
|
||||||
|
|
||||||
let y = 4;
|
let y = 4;
|
||||||
let y = "I can also be bound to text!"; // y is now of a different type
|
let y = "I can also be bound to text!"; // `y` is now of a different type.
|
||||||
```
|
```
|
||||||
|
|
|
@ -17,7 +17,7 @@ situation, this is just convention.)
|
||||||
There’s an alternate form of `vec!` for repeating an initial value:
|
There’s an alternate form of `vec!` for repeating an initial value:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let v = vec![0; 10]; // ten zeroes
|
let v = vec![0; 10]; // A vector of ten zeroes.
|
||||||
```
|
```
|
||||||
|
|
||||||
Vectors store their contents as contiguous arrays of `T` on the heap. This means
|
Vectors store their contents as contiguous arrays of `T` on the heap. This means
|
||||||
|
@ -46,10 +46,10 @@ let v = vec![1, 2, 3, 4, 5];
|
||||||
let i: usize = 0;
|
let i: usize = 0;
|
||||||
let j: i32 = 0;
|
let j: i32 = 0;
|
||||||
|
|
||||||
// works
|
// Works:
|
||||||
v[i];
|
v[i];
|
||||||
|
|
||||||
// doesn’t
|
// Doesn’t:
|
||||||
v[j];
|
v[j];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue