Fundamental-Types
There are many, many types of books in the world, which makes good sense, because there are many, many types of people, and everybody wants to read something different. —Lemony Snicke > >
Fixed-Width Numeric Types
// 10_u8.checked_mul(10).expect("数值溢出");
// 100_u8.checked_add(200).expect("");
// let x = 100_u8;
// let y = 100_u8;
// // Do the addition; panic if it overflows.
// let sum = x.checked_add(y).unwrap();
// 超出不报错
500_u16.wrapping_mul(500); // 53392
500_i16.wrapping_mul(500); // -12144
// In bitwise shift operations, the shift distance
// is wrapped to fall within the size of the value.
// So a shift of 17 bits in a 16-bit type is a shift
// of 1.
// assert_eq!(5_i16.wrapping_shl(17), 10);
Characters
assert_eq!('*' as i32, 42);
assert_eq!('ಠ' as u16, 0xca0);
assert_eq!('ಠ' as i8, -0x60); // U+0CA0 truncated to eight bits, signed
assert_eq!('*'.is_alphabetic(), false);
assert_eq!('β'.is_alphabetic(), true);
assert_eq!('8'.to_digit(10), Some(8));
assert_eq!('ಠ'.len_utf8(), 3);
assert_eq!(std::char::from_digit(2, 10), Some('2'));
Tuples
let text = "I see the eigenvalue in thine eye";
let (head, tail) = text.split_at(21);
assert_eq!(head, "I see the eigenvalue ");
assert_eq!(tail, "in thine eye");
let text = "I see the eigenvalue in thine eye";
let temp = text.split_at(21);
let head = temp.0;
let tail = temp.1;
assert_eq!(head, "I see the eigenvalue ");
assert_eq!(tail, "in thine eye");
Slices
let v: Vec<f64> = vec![0.0, 0.707, 1.0, 0.707];
let a: [f64; 4] = [0.0, -0.707, -1.0, -0.707];
let sv: &[f64] = &v;
let sa: &[f64] = &a;
Error: The variable `sv` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
[E0597] Error: `a` does not live long enough
╭─[command_23:1:1]
│
2 │ let a: [f64; 4] = [0.0, -0.707, -1.0, -0.707];
│ ┬
│ ╰── binding `a` declared here
│
4 │ let sa: &[f64] = &a;
│ ─┬
│ ╰── borrowed value does not live long enough
│ │
│ ╰── cast requires that `a` is borrowed for `'static`
───╯
String Literals
println!("In the room the women come and go,
Singing of Mount Abora");
println!("It was a bright, cold day in April, and \
there were four of us—\
more or less.");
let default_win_install_path = r"C:\Program Files\Gorillas";
println!(r###"
This raw string started with 'r###"'.
Therefore it does not end until we reach a quote mark ('"')
followed immediately by three pound signs ('###'):
"###);
In the room the women come and go,
Singing of Mount Abora
It was a bright, cold day in April, and there were four of us—more or less.
This raw string started with 'r###"'.
Therefore it does not end until we reach a quote mark ('"')
followed immediately by three pound signs ('###'):
Byte Strings
let method = b"GET";
assert_eq!(method, &[b'G', b'E', b'T']);
Strings
let noodles = "noodles".to_string();
let oodles = &noodles[1..];
let poodles = "ಠ_ಠ";
let oodles = &noodles[1..];
let oodles = &noodles[1..];
^^^^^^
The variable `oodles` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
assert_eq!("ಠ_ಠ".len(), 7);
assert_eq!("ಠ_ಠ".chars().count(), 3)
()
let error_message = "too many pets".to_string();
println!("{}",error_message)
too many pets
()
format string
println!("{}",format!("{}°{:02}′{:02}″N", 24, 5, 23))
24°05′23″N
()
let bits = vec!["veni", "vidi", "vici"];
bits.concat()
"venividivici"
bits.join(",")
"veni,vidi,vici"
"ONE".to_lowercase()
"one"
"peanut".contains("nut")
true
"ಠ_ಠ".replace("ಠ", "■")
"■_■"
Ownership-and-Moves
Ownership
{
let point = Box::new((0.625, 0.5)); // point allocated here
let label = format!("{:?}", point); // label allocated here
assert_eq!(label, "(0.625, 0.5)");
}
()
struct Person { name: String, birth: i32 }
let mut composers = Vec::new();
composers.push(Person {
name: "Abc".to_string(),
birth: 123,
});
composers.push(Person {
name: "DEF".to_string(),
birth: 444,
});
composers.push(Person {
name: "ASD".to_string(),
birth: 555,
});
for composer in &composers {
println!("{}, born {}", composer.name, composer.birth);
}
Abc, born 123
DEF, born 444
ASD, born 555
()
Moves
let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
let t = s;
let u = s;
[E0382] Error: use of moved value: `s`
╭─[command_4:1:1]
│
1 │ let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
│ ┬
│ ╰── move occurs because `s` has type `Vec<String>`, which does not implement the `Copy` trait
2 │ let t = s;
│ ┬│
│ ╰── value moved here
│ │
│ ╰─ help: consider cloning the value if the performance cost is acceptable: `.clone()`
3 │ let u = s;
│ ┬
│ ╰── value used here after move
───╯
let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];
let t = s.clone();
let u = s.clone();
More Operations That Move
let mut s = "Govinda".to_string();
s = "Siddhartha".to_string(); // value "Govinda" dropped here
let mut s = "Govinda".to_string();
let t = s;
s = "Siddhartha".to_string(); // nothing is dropped here
Moves and Control Flow
Moves and Indexed Content
// Build a vector of the strings "101", "102", ... "105"
let mut v = Vec::new();
for i in 101 .. 106 {
v.push(i.to_string());
}
()
// Pull out random elements from the vector.
let third = v[2]; // error: Cannot move out of index of Vec
let fifth = v[4]; // here too
[E0507] Error: cannot move out of index of `Vec<String>`
╭─[command_9:1:1]
│
2 │ let third = v[2]; // error: Cannot move out of index of Vec
│ ┬─┬─
│ ╰───── help: consider borrowing here: `&`
│ │
│ ╰─── move occurs because value has type `String`, which does not implement the `Copy` trait
───╯
[E0507] Error: cannot move out of index of `Vec<String>`
╭─[command_9:1:1]
│
3 │ let fifth = v[4]; // here too
│ ┬─┬─
│ ╰───── help: consider borrowing here: `&`
│ │
│ ╰─── move occurs because value has type `String`, which does not implement the `Copy` trait
───╯
// 1. Pop a value off the end of the vector:
let fifth = v.pop().expect("vector empty!");
assert_eq!(fifth, "105");
// 2. Move a value out of a given index in the vector,
// and move the last element into its spot:
let second = v.swap_remove(1);
assert_eq!(second, "102");
// 3. Swap in another value for the one we're taking out:
let third = std::mem::replace(&mut v[2], "substitute".to_string());
assert_eq!(third, "103");
// Let's see what's left of our vector.
assert_eq!(v, vec!["101", "104", "substitute"]);
struct Person { name: Option<String>, birth: i32 }
let mut composers = Vec::new();
composers.push(Person { name: Some("Palestrina".to_string()),
birth: 1525 });
let first_name = composers[0].name;
[E0507] Error: cannot move out of index of `Vec<Person>`
╭─[command_13:1:1]
│
1 │ let first_name = composers[0].name;
│ ┬───────┬────────
│ ╰────────────────── help: consider borrowing here: `&`
│ │
│ ╰────────── move occurs because value has type `Option<String>`, which does not implement the `Copy` trait
───╯
let first_name = std::mem::replace(&mut composers[0].name, None);
assert_eq!(first_name, Some("Palestrina".to_string()));
assert_eq!(composers[0].name, None);
let first_name = composers[0].name.take();
Copy Types: The Exception to Moves
let string1 = "somnambulance".to_string();
let string2 = string1;
let num1: i32 = 36;
let num2 = num1;
struct Label { number: u32 }
fn print(l: Label) { println!("STAMP: {}", l.number); }
let l = Label { number: 3 };
print(l);
println!("My label number is: {}", l.number);
[E0382] Error: borrow of moved value: `l`
╭─[command_17:1:1]
│
3 │ let l = Label { number: 3 };
│ ┬
│ ╰── move occurs because `l` has type `Label`, which does not implement the `Copy` trait
4 │ print(l);
│ ┬
│ ╰── value moved here
5 │ println!("My label number is: {}", l.number);
│ ────┬───
│ ╰───── value borrowed here after move
───╯
#[derive(Copy, Clone)]
struct Label { number: u32 }
#[derive(Copy, Clone)]
struct StringLabel { name: String }
[E0204] Error: the trait `Copy` cannot be implemented for this type
╭─[command_19:1:1]
│
1 │ #[derive(Copy, Clone)]
│ ──┬─
│ ╰─── error: the trait `Copy` cannot be implemented for this type
2 │ struct StringLabel { name: String }
│ ──────┬─────
│ ╰─────── this field does not implement `Copy`
───╯
Rc and Arc: Shared Ownership
use std::rc::Rc;
// Rust can infer all these types; written out for clarity
let s: Rc<String> = Rc::new("shirataki".to_string());
let t: Rc<String> = s.clone();
let u: Rc<String> = s.clone();
assert!(s.contains("shira"));
assert_eq!(t.find("taki"), Some(5));
println!("{} are quite chewy, almost bouncy, but lack flavor", u);
shirataki are quite chewy, almost bouncy, but lack flavor
s.push_str(" noodles");
[E0596] Error: cannot borrow data in an `Rc` as mutable
╭─[command_22:1:1]
│
1 │ s.push_str(" noodles");
│ ┬
│ ╰── cannot borrow as mutable
│
│ Note: You can change an existing variable to mutable like: `let mut x = x;`
───╯
References
Libraries cannot provide new inabilities. —Mark Miller
use std::collections::HashMap;
type Table = HashMap<String, Vec<String>>;
fn show(table:Table) {
for (artist,works) in table {
println!("works by {}",artist);
for work in works {
println!(" {}",work);
}
}
}
let mut table = Table::new();
table.insert("Gesualdo".to_string(),
vec!["many madrigals".to_string(),
"Tenebrae Responsoria".to_string()]);
table.insert("Caravaggio".to_string(),
vec!["The Musicians".to_string(),
"The Calling of St. Matthew".to_string()]);
table.insert("Cellini".to_string(),
vec!["Perseus with the head of Medusa".to_string(),
"a salt cellar".to_string()]);
show(table);
works by Gesualdo
many madrigals
Tenebrae Responsoria
works by Caravaggio
The Musicians
The Calling of St. Matthew
works by Cellini
Perseus with the head of Medusa
a salt cellar
fn sort_works(table: &mut Table) {
for (_artist, works) in table {
works.sort();
}
}
let mut table = Table::new();
table.insert("Gesualdo".to_string(),
vec!["many madrigals".to_string(),
"Tenebrae Responsoria".to_string()]);
table.insert("Caravaggio".to_string(),
vec!["The Musicians".to_string(),
"The Calling of St. Matthew".to_string()]);
table.insert("Cellini".to_string(),
vec!["Perseus with the head of Medusa".to_string(),
"a salt cellar".to_string()]);
sort_works(&mut table);
Assigning References
let x = 10;
let y = 20;
let mut r = &x;
if true { r = &y; }
assert!(*r == 10 || *r == 20);
Error: The variable `r` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
Error: The variable `r` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
References to References
{
struct Point { x: i32, y: i32 }
let point = Point { x: 1000, y: 729 };
let r: &Point = &point;
let rr: &&Point = &r;
let rrr: &&&Point = &rr;
assert_eq!(rrr.y, 729);
}
()
Comparing References
{
let x = 10;
let y = 10;
let rx = &x;
let ry = &y;
let rrx = ℞
let rry = &ry;
assert!(rrx <= rry);
assert!(rrx == rry);
assert!(rx == ry); // their referents are equal
assert!(!std::ptr::eq(rx, ry)); // but occupy different addresses
assert!(rx == rrx); // error: type mismatch: `&i32` vs `&&i32`
assert!(rx == *rrx); // this is okay
}
[E0277] Error: can't compare `{integer}` with `&{integer}`
╭─[command_19:1:1]
│
13 │ assert!(rx == rrx); // error: type mismatch: `&i32` vs `&&i32`
│ ─┬
│ ╰── no implementation for `{integer} == &{integer}`
────╯
Borrowing a Local Variable
{
let r;
{
let x = 1;
r = &x;
}
assert_eq!(*r,1);
}
[E0597] Error: `x` does not live long enough
╭─[command_20:1:1]
│
4 │ let x = 1;
│ ┬
│ ╰── binding `x` declared here
5 │ r = &x;
│ ─┬
│ ╰── borrowed value does not live long enough
6 │ }
│ ┬
│ ╰── `x` dropped here while still borrowed
7 │ assert_eq!(*r,1);
│ ────────┬───────
│ ╰───────── borrow later used here
───╯
Receiving References as Function Arguments
// This code has several problems, and doesn't compile.
static mut STASH: &i32;
fn f(p: &i32) { STASH = p; }
Error: free static item without body
╭─[command_21:1:1]
│
2 │ static mut STASH: &i32;
│ ───────────┬──────────┬
│ ╰───────────── error: free static item without body
│ │
│ ╰── help: provide a definition for the static: ` = <expr>;`
───╯
static mut STASH: &i32 = &128;
fn f(p: &i32) { // still not good enough
unsafe {
STASH = p;
}
}
Error: lifetime may not live long enough
╭─[command_22:1:1]
│
2 │ fn f(p: &i32) { // still not good enough
│ ┬
│ ╰── let's call the lifetime of this reference `'1`
│
4 │ STASH = p;
│ ────┬────
│ ╰────── assignment requires that `'1` must outlive `'static`
───╯
static mut STASH: &i32 = &10;
fn f(p: &'static i32) {
unsafe {
STASH = p;
println!("{}",STASH);
}
}
static WORTH_POINTING_AT: i32 = 1000;
f(&WORTH_POINTING_AT);
1000
{
unsafe {
println!("{}",STASH);
println!("{}",WORTH_POINTING_AT);
}
}
10
1000
()
Passing References to Functions
// This could be written more briefly: fn g(p: &i32),
// but let's write out the lifetimes for now.
fn g<'a>(p: &'a i32) { }
let x = 10;
g(&x);
fn f(p: &'static i32) { }
let x = 10;
f(&x);
// This fails to compile: the reference &x must not outlive x, but by passing it to f, we
// constrain it to live at least as long as 'static. There’s no way to satisfy everyone here,
// so Rust rejects the code.
fn f(p: &'static i32) { }
^ warning: unused variable: `p`
unused variable: `p`
help: if this is intentional, prefix it with an underscore
_p
warning: unused variable: `p`
unused variable: `p`
help: if this is intentional, prefix it with an underscore
_p
f(&x);
^^ borrowed value does not live long enough
let x = 10;
^ binding `x` declared here
f(&x);
^^^^^ argument requires that `x` is borrowed for `'static`
`x` does not live long enough
Returning References
fn smallest(v: &[i32]) -> &i32 {
let mut s = &v[0];
for r in &v[1..] {
if *r < *s { s = r; }
}
s
}
// fn smallest<'a>(v: &'a [i32]) -> &'a i32 { }
let s;
{
let parabola = [9, 4, 1, 0, 1, 4, 9];
s = smallest(¶bola);
}
assert_eq!(*s, 0);
[unused_variables] Error: unused variable: `p`
[E0597] Error: `parabola` does not live long enough
╭─[command_42:1:1]
│
3 │ let parabola = [9, 4, 1, 0, 1, 4, 9];
│ ────┬───
│ ╰───── binding `parabola` declared here
4 │ s = smallest(¶bola);
│ ────┬────
│ ╰────── borrowed value does not live long enough
│ │
│ ╰────── cast requires that `parabola` is borrowed for `'static`
5 │ }
│ ┬
│ ╰── `parabola` dropped here while still borrowed
───╯
{
let parabola = [9, 4, 1, 0, 1, 4, 9];
let s = smallest(¶bola);
assert_eq!(*s, 0); // fine: parabola still alive
}
()
Structs Containing References
// This does not compile.
struct S {
r: &i32
}
let s;
{
let x = 10;
s = S { r: &x };
}
assert_eq!(*s.r, 10); // bad: reads from dropped `x`
[E0106] Error: missing lifetime specifier
╭─[command_44:1:1]
│
3 │ r: &i32
│ ┬
│ ╰── expected named lifetime parameter
───╯
struct S<'a> {
r: &'a i32
}
{
let s;
{
let x = 10;
s = S { r: &x };
}
assert_eq!(*s.r, 10);
}
[unused_variables] Error: unused variable: `p`
[E0597] Error: `x` does not live long enough
╭─[command_49:1:1]
│
7 │ let x = 10;
│ ┬
│ ╰── binding `x` declared here
8 │ s = S { r: &x };
│ ─┬
│ ╰── borrowed value does not live long enough
9 │ }
│ ┬
│ ╰── `x` dropped here while still borrowed
10 │ assert_eq!(*s.r, 10);
│ ──────────┬─────────
│ ╰─────────── borrow later used here
────╯
Distinct Lifetime Parameters
struct S<'a> {
x: &'a i32,
y: &'a i32
}
{
let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x;
}
}
println!("{}", r);
}
[unused_variables] Error: unused variable: `p`
[E0597] Error: `y` does not live long enough
╭─[command_56:1:1]
│
5 │ let y = 20;
│ ┬
│ ╰── binding `y` declared here
│
7 │ let s = S { x: &x, y: &y };
│ ─┬
│ ╰── borrowed value does not live long enough
│
10 │ }
│ ┬
│ ╰── `y` dropped here while still borrowed
11 │ println!("{}", r);
│ ┬
│ ╰── borrow later used here
────╯
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
{
let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x;
}
}
println!("{}", r);
}
10
()
fn f<'a>(r: &'a i32, s: &'a i32) -> &'a i32 { r } // perhaps too tight
fn f<'a, 'b>(r: &'a i32, s: &'b i32) -> &'a i32 { r } // looser
fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }
[E0261] Error: use of undeclared lifetime name `'a`
╭─[command_64:1:1]
│
1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }
│ │ ─┬
│ ╰────────── help: consider introducing lifetime `'a` here: `'a, `
│ │
│ ╰── undeclared lifetime
───╯
[E0261] Error: use of undeclared lifetime name `'b`
╭─[command_64:1:1]
│
1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }
│ │ ─┬
│ ╰────────────────────── help: consider introducing lifetime `'b` here: `'b, `
│ │
│ ╰── undeclared lifetime
───╯
[E0261] Error: use of undeclared lifetime name `'a`
╭─[command_64:1:1]
│
1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }
│ │ ─┬
│ ╰────────────────────────────────── help: consider introducing lifetime `'a` here: `'a, `
│ │
│ ╰── undeclared lifetime
───╯
[non_camel_case_types] Error: type parameter `b` should have an upper camel case name
╭─[command_64:1:1]
│
1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }
│ ┬
│ ╰── warning: type parameter `b` should have an upper camel case name
│ │
│ ╰── help: convert the identifier to upper camel case: `B`
───╯
Omitting Lifetime Parameters
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
fn sum_r_xy(r: &i32, s: S) -> i32 {
r + s.x + s.y
}
// fn sum_r_xy<'a, 'b, 'c>(r: &'a i32, s: S<'b, 'c>) -> i32
fn first_third(point: &[i32; 3]) -> (&i32, &i32) {
(&point[0], &point[2])
}
// fn first_third<'a>(point: &'a [i32; 3]) -> (&'a i32, &'a i32)
struct StringTable {
elements: Vec<String>,
}
impl StringTable {
fn find_by_prefix(&self,prefix:&str) -> Option<&String> {
for i in 0..self.elements.len() {
if self.elements[i].starts_with(prefix) {
return Some(&self.elements[i]);
}
}
None
}
}
// fn find_by_prefix<'a, 'b>(&'a self, prefix: &'b str) -> Option<&'a String>
Sharing Versus Mutation
let v = vec![4, 8, 19, 27, 34, 10];
let r = &v;
let aside = v; // move vector to aside
r[0]; // bad: uses `v`, which is now uninitialized
[unused_variables] Error: unused variable: `s`
[unused_variables] Error: unused variable: `p`
Error: The variable `r` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
let v = vec![4, 8, 19, 27, 34, 10];
{
let r = &v;
r[0]; // ok: vector is still there
}
let aside = v;
fn extend(vec: &mut Vec<f64>, slice: &[f64]) {
for elt in slice {
vec.push(*elt);
}
}
let mut wave = Vec::new();
let head = vec![0.0, 1.0];
let tail = [0.0, -1.0];
extend(&mut wave, &head); // extend wave with another vector
extend(&mut wave, &tail); // extend wave with an array
assert_eq!(wave, vec![0.0, 1.0, 0.0, -1.0]);
extend(&mut wave, &wave);
assert_eq!(wave, vec![0.0, 1.0, 0.0, -1.0,
0.0, 1.0, 0.0, -1.0])
[unused_variables] Error: unused variable: `s`
[unused_variables] Error: unused variable: `p`
[E0502] Error: cannot borrow `wave` as immutable because it is also borrowed as mutable
╭─[command_83:1:1]
│
1 │ extend(&mut wave, &wave);
│ ───┬── ────┬──── ──┬──
│ ╰───────────────────── mutable borrow later used by call
│ │ │
│ ╰───────────── mutable borrow occurs here
│ │
│ ╰──── immutable borrow occurs here
───╯
Taking Arms Against a Sea of Objects
struct-enums-patterns
Long ago, when shepherds wanted to see if two herds of sheep were isomorphic, they would look for an explicit isomorphism. —John C. Baez and James Dolan, “
Named-Field Structs
// A rectangle of eight-bit grayscale pixels.
struct GrayscaleMap {
pixels: Vec<u8>,
size: (usize, usize)
}
let width = 1024;
let height = 576;
let image = GrayscaleMap {
pixels: vec![0; width * height],
size: (width, height)
};
image
[E0277] Error: `GrayscaleMap` doesn't implement `Debug`
/// A rectangle of eight-bit grayscale pixels.
// 模块外访问
pub struct GrayscaleMap {
pub pixels: Vec<u8>,
pub size: (usize, usize)
}
Tuple-Like Structs
#[derive(Copy, Clone, Debug)]
struct Bounds(usize, usize);
let image_bounds = Bounds(1024, 768);
image_bounds
The type of the variable image was redefined, so was lost.
Bounds(1024, 768)
Unit-Like Structs
struct A;
let a=A;
Struct Layout 内存布局
Defining Methods with impl
/// A first-in, first-out queue of characters.
pub struct Queue {
older: Vec<char>, // older elements, eldest last.
younger: Vec<char> // younger elements, youngest last.
}
impl Queue {
pub fn push(&mut self,c: char) {
self.younger.push(c);
}
pub fn pop(&mut self) -> Option<char> {
if self.older.is_empty() {
if self.younger.is_empty() {
return None;
}
use std::mem::swap;
swap(&mut self.older,&mut self.younger);
self.older.reverse();
}
self.older.pop()
}
}
let mut q = Queue { older: Vec::new(), younger: Vec::new() };
q.push('0');
q.push('1');
assert_eq!(q.pop(), Some('0'));
q.push('∞');
assert_eq!(q.pop(), Some('1'));
assert_eq!(q.pop(), Some('∞'));
assert_eq!(q.pop(), None);
impl Queue {
pub fn is_empty(&self) -> bool {
self.older.is_empty() && self.younger.is_empty()
}
}
assert!(q.is_empty());
q.push('☉');
assert!(!q.is_empty());
impl Queue {
pub fn split(self) -> (Vec<char>, Vec<char>) {
(self.older, self.younger)
}
}
let mut q = Queue { older: Vec::new(), younger: Vec::new() };
q.push('P');
q.push('D');
assert_eq!(q.pop(), Some('P'));
q.push('X');
let (older, younger) = q.split();
// q is now uninitialized.
assert_eq!(older, vec!['D']);
assert_eq!(younger, vec!['X'])
()
q
[E0425] Error: cannot find value `q` in this scope
╭─[command_23:1:1]
│
1 │ q
│ ┬
│ ╰── error: cannot find value `q` in this scope
│ │
│ ╰── help: a unit struct with a similar name exists: `A`
───╯
impl Queue {
fn new() -> Queue {
Queue { older: Vec::new(), younger: Vec::new() }
}
}
let mut bq = Box::new(Queue::new());
bq.push('A')
()
use std::rc::Rc;
struct Node {
tag: String,
children: Vec<Rc<Node>>
}
impl Node {
fn new(tag: &str) ->Node {
Node {
tag: tag.to_string(),
children: vec![],
}
}
}
impl Node {
fn append_to(self: Rc<Self>, parent: &mut Node) {
parent.children.push(self);
}
}
let shared_node = Rc::new(Node::new("first"));
pub struct Vector2 {
x: f32,
y: f32,
}
impl Vector2 {
const ZERO: Vector2 = Vector2 { x: 0.0, y: 0.0 };
const UNIT: Vector2 = Vector2 { x: 1.0, y: 0.0 };
}
let scaled = Vector2::UNIT.x;
Generic Structs
pub struct TheQueue<T> {
older: Vec<T>,
younger: Vec<T>
}
impl<T> TheQueue<T> {
pub fn new() -> TheQueue<T> {
TheQueue { older: Vec::new(), younger: Vec::new() }
}
pub fn push(&mut self, t: T) {
self.younger.push(t);
}
pub fn is_empty(&self) -> bool {
self.older.is_empty() && self.younger.is_empty()
}
}
impl TheQueue<f64> {
fn sum(&self) -> f64 {
0_f64
}
}
let mut q = TheQueue::<char>::new();
q.push('a');
Structs with Lifetime Parameters
struct Extrema<'elt> {
greatest: &'elt i32,
least: &'elt i32,
}
fn find_extrema<'s>(slice: &'s [i32]) -> Extrema<'s> {
let mut greatest = &slice[0];
let mut least = &slice[0];
for i in 1..slice.len() {
if slice[i] < *least { least = &slice[i]; }
if slice[i] > *greatest { greatest = &slice[i]; }
}
Extrema { greatest, least }
}
Deriving Common Traits for Struct Types
#[derive(Copy, Clone, Debug, PartialEq)]
struct Point {
x: f64,
y: f64
}
{
use std::cell::RefCell;
let ref_cell: RefCell<String> = RefCell::new("hello".to_string());
let r = ref_cell.borrow();
let count = r.len();
assert_eq!(count,5);
let mut w = ref_cell.borrow_mut();
w.push_str("world");
}
thread '<unnamed>' panicked at src/lib.rs:247:22:
already borrowed: BorrowMutError
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::cell::panic_already_borrowed
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/cell.rs:762:5
3: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
4: run_user_code_39
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Enums and Patterns
use std::cmp::Ordering;
fn compare(a: i32,b: i32) -> Ordering {
if a > b {
Ordering::Greater
} else if a < b {
Ordering::Less
} else {
Ordering::Equal
}
}
enum HttpStatus {
Ok = 200,
NotModified = 304,
NotFound = 404,
}
use std::mem::size_of;
assert_eq!(size_of::<Ordering>(), 1);
assert_eq!(size_of::<HttpStatus>(), 2); // 404 doesn't fit in a u8
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum TimeUnit {
Seconds, Minutes, Hours, Days, Months, Years,
}
impl TimeUnit {
/// Return the plural noun for this time unit.
fn plural(self) -> &'static str {
match self {
TimeUnit::Seconds => "seconds",
TimeUnit::Minutes => "minutes",
TimeUnit::Hours => "hours",
TimeUnit::Days => "days",
TimeUnit::Months => "months",
TimeUnit::Years => "years",
}
}
/// Return the singular noun for this time unit.
fn singular(self) -> &'static str {
self.plural().trim_end_matches('s')
}
}
Enums in Memory
Patterns
enum RoughTime {
InThePast(TimeUnit, u32),
JustNow,
InTheFuture(TimeUnit, u32),
}
fn rough_time_to_english(rt: RoughTime) -> String {
match rt {
RoughTime::InThePast(units, count) =>
format!("{} {} ago", count, units.plural()),
RoughTime::JustNow =>
format!("just now"),
RoughTime::InTheFuture(units, count) =>
format!("{} {} from now", count, units.plural()),
}
}
fn greet_people(names: &[&str]) {
match names {
[] => { println!("Hello, nobody.") },
[a] => { println!("Hello, {}.", a) },
[a, b] => { println!("Hello, {} and {}.", a, b) },
[a, .., b] => { println!("Hello, everyone from {} to {}.", a, b) }
}
}
// An ordered collection of `T`s.
enum BinaryTree<T> {
Empty,
NonEmpty(Box<TreeNode<T>>),
}
// A part of a BinaryTree.
struct TreeNode<T> {
element: T,
left: BinaryTree<T>,
right: BinaryTree<T>,
}
impl <T: Ord> BinaryTree<T> {
fn add(&mut self,value :T) {
match *self {
BinaryTree::Empty => {
*self = BinaryTree::NonEmpty(Box::new(
TreeNode {
element: value,
left: BinaryTree::Empty,
right: BinaryTree::Empty,
}
))
},
BinaryTree::NonEmpty(ref mut node) => {
if value <= node.element {
node.left.add(value);
} else {
node.right.add(value);
}
}
}
}
}
Structs
LISP programmers know the value of everything, but the cost of nothing. —Alan Perlis, epigram > >
Error Handling
I knew if I stayed around long enough, something like this would happen. —George Bernard Shaw on dying
use std::error::Error;
use std::io::{Write,stderr};
fn print_error(mut err: &dyn Error) {
let _ = writeln!(stderr(),"error: {}",err);
while let Some(source) = err.source() {
let _ = writeln!(stderr(),"cased by :{}",source);
err = source;
}
}
let weather = match get_weather(hometown) {
Ok(success_value) => success_value,
Err(err) => return Err(err)
};
Crates and Modules
mod spores {
use cells::{Cell, Gene};
/// A cell made by an adult fern. It disperses on the wind as part of
/// the fern life cycle. A spore grows into a prothallus -- a whole
/// separate organism, up to 5mm across -- which produces the zygote
/// that grows into a new fern. (Plant sex is complicated.)
pub struct Spore {
...
}
/// Simulate the production of a spore by meiosis.
pub fn produce_spore(factory: &mut Sporangium) -> Spore {
...
}
/// Extract the genes in a particular spore.
pub(crate) fn genes(spore: &Spore) -> Vec<Gene> {
...
}
/// Mix genes to prepare for meiosis (part of interphase).
fn recombine(parent: &mut Cell) {
...
}
...
}
bin
Attributes
Test
#[test]
fn trig_works() {
use std::f64::consts::PI;
assert!(roughly_equal(PI.sin(), 0.0));
}
```rust
#[cfg(test)] // 仅当run test时才会include 这个模块
// include this module only when testing
mod tests {
fn roughly_equal(a: f64, b: f64) -> bool {
(a - b).abs() < 1e-6
}
#[test]
fn trig_works() {
use std::f64::consts::PI;
assert!(roughly_equal(PI.sin(), 0.0));
}
}
Documentation
Package Versions
Input and Output
use std::io::{self, Read, Write, ErrorKind};
const DEFAULT_BUF_SIZE: usize = 8 * 1024;
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W)
-> io::Result<u64>
where R: Read,W: Write
{
let mut buf = [0; DEFAULT_BUF_SIZE];
let mut writern = 0;
loop {
let len = match reader.read(&mut buf) {
Ok(0) => return Ok(writern),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
writer.write_all(&buf[..len])?;
writern += len as u64;
}
}
use std::io;
use std::io::prelude::*;
fn grep(target: &str) -> io::Result<()> {
let stdin = io::stdin();
for line_result in stdin.lock().lines() {
let line = line_result?;
if line.contains(target) {
println!("{}",line);
}
}
Ok(())
}
fn grep<R>(target: &str, reader: R) -> io::Result<()>
where R: BufRead
{
for line_result in reader.lines() {
let line = line_result?;
if line.contains(target) {
println!("{}", line);
}
}
Ok(())
}
// let stdin = io::stdin();
// grep(&target, stdin.lock())?; // ok
// let f = File::open(file)?;
// grep(&target, BufReader::new(f))?; // also o
use std::fs::OpenOptions;
let log = OpenOptions::new()
.append(true)
.open("server.log").unwrap_err();
let file = OpenOptions::new()
.write(true)
.create_new(true)
.open("new_file.log").unwrap_err();
thread '<unnamed>' panicked at src/lib.rs:138:27:
called `Result::unwrap_err()` on an `Ok` value: File { fd: 3, path: "/home/realcpf/Documents/rustRepos/rust-prog-2021/new_file.log", read: false, write: true }
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::result::unwrap_failed
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/result.rs:1652:5
3: <unknown>
4: <unknown>
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
use std::process::{Command, Stdio};
let mut child =
Command::new("grep")
.arg("-e")
.arg("a.*e.*i.*o.*u")
.stdin(Stdio::piped())
.spawn()?;
let mut to_child = child.stdin.take().unwrap();
for word in my_words {
writeln!(to_child, "{}", word)?;
}
drop(to_child); // close grep's stdin, so it will exit
child.wait()?;
[E0425] Error: cannot find value `my_words` in this scope
╭─[command_12:1:1]
│
9 │ for word in my_words {
│ ────┬───
│ ╰───── not found in this scope
───╯
use std::path::Path;
let home_dir = Path::new("/home/realcpf");
assert_eq!(home_dir.parent(),Some(Path::new("/home")));
use std::ffi::OsStr;
assert_eq!(Path::new("/home/fwolfe/program.txt").file_name(),
Some(OsStr::new("program.txt")));
let path1 = Path::new("/usr/share/dict");
assert_eq!(path1.join("words"),
Path::new("/usr/share/dict/words"));
let file = Path::new("/home/jimb/calendars/calendar-18x18.pdf");
assert_eq!(file.ancestors().collect::<Vec<_>>(),
vec![Path::new("/home/jimb/calendars/calendar-18x18.pdf"),
Path::new("/home/jimb/calendars"),
Path::new("/home/jimb"),
Path::new("/home"),
Path::new("/")])
()
use std::fs;
use std::io;
use std::path::Path;
/// Copy wha tever is at `src` to the target path `dst`.
fn copy_to(src: &Path, src_type: &fs::FileType, dst: &Path)
-> io::Result<()>
{
if src_type.is_file() {
fs::copy(src, dst)?;
} else if src_type.is_dir() {
copy_dir_to(src, dst)?;
} else {
return Err(io::Error::new(io::ErrorKind::Other,
format!("don't know how to copy: {}",
src.display())));
}
Ok(())
}
// Copy the existing directory `src` to the target path `dst`.
fn copy_dir_to(src: &Path, dst: &Path) -> io::Result<()> {
if !dst.is_dir() {
fs::create_dir(dst)?;
}
for entry_result in src.read_dir()? {
let entry = entry_result?;
let file_type = entry.file_type()?;
copy_to(&entry.path(), &file_type, &dst.join(entry.file_name()))?;
}
Ok(())
}
#[cfg(unix)]
use std::os::unix::fs::symlink;
/// Stub implementation of `symlink` for platforms that don't provide it.
#[cfg(not(unix))]
fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, _dst: Q)
-> std::io::Result<()>
{
Err(io::Error::new(io::ErrorKind::Other,
format!("can't copy symbolic link: {}",
src.as_ref().display())))
}
use std::net::TcpListener;
use std::io;
use std::thread::spawn;
/// Accept connections forever, spawning a thread for each one.
fn echo_main(addr: &str) -> io::Result<()> {
let listener = TcpListener::bind(addr)?;
println!("listening on {}", addr);
loop {
// Wait for a client to connect.
let (mut stream, addr) = listener.accept()?;
println!("connection received from {}", addr);
// Spawn a thread to handle this client.
let mut write_stream = stream.try_clone()?;
spawn(move || {
// Echo everything we receive from `stream` back to it.
io::copy(&mut stream, &mut write_stream)
.expect("error in client thread: ");
println!("connection closed");
});
}
}
fn main() {
echo_main("127.0.0.1:17007").expect("error: ");
}
use std::error::Error;
use std::io;
fn http_get_main(url: &str) -> Result<(), Box<dyn Error>> {
// Send the HTTP request and get a response.
let mut response = reqwest::blocking::get(url)?;
if !response.status().is_success() {
Err(format!("{}", response.status()))?;
}
// Read the response body and write it to stdout.
let stdout = io::stdout();
io::copy(&mut response, &mut stdout.lock())?;
Ok(())
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() != 2 {
eprintln!("usage: http-get URL");
return;
}
if let Err(err) = http_get_main(&args[1]) {
eprintln!("error: {}", err);
}
}
```rust
Strings and Text
assert_eq!("うどん: udon".as_bytes(),
&[0xe3, 0x81, 0x86, //う
0xe3, 0x81, 0xa9, //ど
0xe3, 0x82, 0x93, //ん
0x3a, 0x20, 0x75, 0x64, 0x6f, 0x6e // : udon
]);
assert_eq!(" ערבטוב ".chars().next(), Some('ע'));
thread '<unnamed>' panicked at src/lib.rs:6:1:
assertion `left == right` failed
left: Some(' ')
right: Some('ע')
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::panicking::assert_failed_inner
3: <unknown>
4: <unknown>
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
assert_eq!("カニ".chars().next(), Some('カ'))
()
assert!(32u8.is_ascii_whitespace());
assert!(b'9'.is_ascii_digit())
()
// char::is_ascii_whitespace函数实现了许多Web标准通用的空格定义,
// 而char::is_whitespace遵循Unicode标准。
let line_tab = '\u{000b}'; // 'line tab', AKA 'vertical tab'
assert_eq!(line_tab.is_whitespace(), true);
assert_eq!(line_tab.is_ascii_whitespace(), false)
()
assert_eq!('F'.to_digit(16), Some(15));
assert_eq!(std::char::from_digit(15, 16), Some('f'));
assert!(char::is_digit('f', 16));
let mut upper = 's'.to_uppercase();
assert_eq!(upper.next(), Some('S'));
assert_eq!(upper.next(), None);
// The uppercase form of the German letter "sharp S" is "SS":
let mut upper = 'ß'.to_uppercase();
assert_eq!(upper.next(), Some('S'));
assert_eq!(upper.next(), Some('S'));
assert_eq!(upper.next(), None);
// Unicode says to lowercase Turkish dotted capital 'İ' to 'i'
// followed by `'\u{307}'`, COMBINING DOT ABOVE, so that a
// subsequent conversion back to uppercase preserves the dot.
let ch = 'İ'; // `'\u{130}'`
let mut lower = ch.to_lowercase();
assert_eq!(lower.next(), Some('i'));
assert_eq!(lower.next(), Some('\u{307}'));
assert_eq!(lower.next(), None)
()
assert_eq!('B' as u32, 66);
assert_eq!('饂' as u8, 66); // upper bits truncated
assert_eq!('二' as i8, -116); // same
assert_eq!(char::from(66), 'B');
assert_eq!(std::char::from_u32(0x9942), Some('饂'));
assert_eq!(std::char::from_u32(0xd800), None); // reserved for UTF-16
let spacey = "man hat tan";
let spaceless: String =
spacey.chars().filter(|c| !c.is_whitespace()).collect();
assert_eq!(spaceless, "manhattan");
let full = "bookkeeping";
assert_eq!(&full[..4], "book");
assert_eq!(&full[5..], "eeping");
assert_eq!(&full[2..4], "ok");
assert_eq!(full[..].len(), 11);
assert_eq!(full[5..].contains("boo"), false)
()
let parenthesized = "Rust (饂)";
assert_eq!(parenthesized[6..].chars().next(), Some('饂'));
let mut also_spaceless = "con".to_string();
also_spaceless.extend("tri but ion".split_whitespace());
assert_eq!(also_spaceless, "contribution");
use std::fmt::Write;
let mut letter = String::new();
writeln!(letter, "Whose {} these are I think I know", "rutabagas")?;
writeln!(letter, "His house is in the village though;")?;
assert_eq!(letter, "Whose rutabagas these are I think I know\n\
His house is in the village though;\n");
let left = "partners".to_string();
let mut right = "crime".to_string();
assert_eq!(left + " in " + &right, "partners in crime");
right += " doesn't pay";
assert_eq!(right, "crime doesn't pay")
()
// 返回给定字节索引范围内的迭代器,并在删除迭代器后删除字符。范围后的字符向前面移动
let mut choco = "chocolate".to_string();
assert_eq!(choco.drain(3..6).collect::<String>(), "col");
assert_eq!(choco, "choate");
let mut beverage = "a piña colada".to_string();
beverage.replace_range(2..7, "kahlua"); // 'ñ' is two bytes!
assert_eq!(beverage, "a kahlua colada");
let haystack = "One fine day, in the middle of the night";
assert_eq!(haystack.find(','), Some(12));
assert_eq!(haystack.find("night"), Some(35));
assert_eq!(haystack.find(char::is_whitespace), Some(3));
assert_eq!("## Elephants"
.trim_start_matches(|ch: char| ch == '#' || ch.is_whitespace()),
"Elephants");
let code = "\t function noodle() { ";
assert_eq!(code.trim_start_matches([' ', '\t'].as_ref()),
"function noodle() { ");
// Shorter equivalent: &[' ', '\t'][..]
assert!("2017".starts_with(char::is_numeric));
let quip = "We also know there are known unknowns";
assert_eq!(quip.find("know"), Some(8));
assert_eq!(quip.rfind("know"), Some(31));
assert_eq!(quip.find("ya know"), None);
assert_eq!(quip.rfind(char::is_uppercase), Some(0));
assert_eq!("The only thing we have to fear is fear itself"
.replace("fear", "spin"),
"The only thing we have to spin is spin itself");
assert_eq!("`Borrow` and `BorrowMut`"
.replace(|ch:char| !ch.is_alphanumeric(), ""),
"BorrowandBorrowMut");
assert_eq!("élan".char_indices().collect::<Vec<_>>(),
vec![(0, 'é'), // has a two-byte UTF-8 encoding
(2, 'l'),
(3, 'a'),
(4, 'n')]);
assert_eq!("élan".bytes().collect::<Vec<_>>(),
vec![195, 169, b'l', b'a', b'n']);
// The ':' characters are separators here. Note the final "".
assert_eq!("jimb:1000:Jim Blandy:".split(':').collect::<Vec<_>>(),
vec!["jimb", "1000", "Jim Blandy", ""]);
// The '\n' characters are terminators here.
assert_eq!("127.0.0.1 localhost\n\
127.0.0.1 www.reddit.com\n"
.split_terminator('\n').collect::<Vec<_>>(),
vec!["127.0.0.1 localhost",
"127.0.0.1 www.reddit.com"]);
// Note, no final ""!
let poem = "This is just to say\n\
I have eaten\n\
the plums\n\
again\n";
assert_eq!(poem.split_whitespace().collect::<Vec<_>>(),
vec!["This", "is", "just", "to", "say",
"I", "have", "eaten", "the", "plums",
"again"]);
assert_eq!("\t*.rs ".trim(), "*.rs");
assert_eq!("\t*.rs ".trim_start(), "*.rs ");
assert_eq!("\t*.rs ".trim_end(), "\t*.rs");
assert_eq!("001990".trim_start_matches('0'), "1990");
use std::str::FromStr;
assert_eq!(usize::from_str("3628800"), Ok(3628800));
assert_eq!(f64::from_str("128.5625"), Ok(128.5625));
assert_eq!(bool::from_str("true"), Ok(true));
assert!(f64::from_str("not a float at all").is_err());
assert!(bool::from_str("TRUE").is_err());
assert_eq!(char::from_str("é"), Ok('é'));
assert!(char::from_str("abcdefg").is_err());
use std::net::IpAddr;
let address = IpAddr::from_str("fe80::0000:3ea9:f4ff:fe34:7a50")?;
assert_eq!(address,
IpAddr::from([0xfe80, 0, 0, 0, 0x3ea9, 0xf4ff, 0xfe34, 0x7a50]));
let address = "fe80::0000:3ea9:f4ff:fe34:7a50".parse::<IpAddr>().unwrap();
assert_eq!(format!("{}, wow", "doge"), "doge, wow");
assert_eq!(format!("{}", true), "true");
assert_eq!(format!("({:.3}, {:.3})", 0.5, f64::sqrt(3.0)/2.0),
"(0.500, 0.866)");
// Using `address` from above.
let formatted_addr: String = format!("{}", address);
assert_eq!(formatted_addr, "fe80::3ea9:f4ff:fe34:7a50");
Producing Text from UTF-8 Data
let good_utf8: Vec<u8> = vec![0xe9, 0x8c, 0x86];
assert_eq!(String::from_utf8(good_utf8).ok(), Some("錆".to_string()));
let bad_utf8: Vec<u8> = vec![0x9f, 0xf0, 0xa6, 0x80];
let result = String::from_utf8(bad_utf8);
assert!(result.is_err());
// Since String::from_utf8 failed, it didn't consume the original
// vector, and the error value hands it back to us unharmed.
assert_eq!(result.unwrap_err().into_bytes(),
vec![0x9f, 0xf0, 0xa6, 0x80])
()
fn get_name() -> String {
std::env::var("USER") // Windows uses "USERNAME"
.unwrap_or("whoever you are".to_string())
}
println!("Greetings, {}!", get_name())
Greetings, realcpf!
()
use std::borrow::Cow;
fn get_name() -> Cow<'static ,str> {
std::env::var("USER")
.map(|v|Cow::Owned(v))
.unwrap_or(Cow::Borrowed("whover you are"))
}
println!("Greetings, {}!", get_name())
Greetings, realcpf!
()
Formatting Values
println!("{:.3}μs: relocated {} at {:#x} to {:#x}, {} bytes",
0.84391, "object",
140737488346304_usize, 6299664_usize, 64);
0.844μs: relocated object at 0x7fffffffdcc0 to 0x602010, 64 bytes
assert_eq!(format!("{{a, c}} ⊂ {{a, b, c}}"),
"{a, c} ⊂ {a, b, c}");
Formatting Text Values
assert_eq!(format!("{:4}", "th\u{e9}"), "th\u{e9} ");
assert_eq!(format!("{:4}", "the\u{301}"), "the\u{301}");
Formatting Numbers
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("Portland", (45.5237606,-122.6819273));
map.insert("Taipei", (25.0375167, 121.5637));
println!("{:?}", map);
{"Taipei": (25.0375167, 121.5637), "Portland": (45.5237606, -122.6819273)}
println!("ordinary: {:02?}", [9, 15, 240]);
println!("hex: {:02x?}", [9, 15, 240]);
ordinary: [09, 15, 240]
hex: [09, 0f, f0]
#[derive(Copy, Clone, Debug)]
struct Complex { re: f64, im: f64 }
let third = Complex { re: -0.5, im: f64::sqrt(0.75) };
println!("{:?}", third)
Complex { re: -0.5, im: 0.8660254037844386 }
()
Formatting Pointers for Debugging
use std::rc::Rc;
let original = Rc::new("mazurka".to_string());
let cloned = original.clone();
let impostor = Rc::new("mazurka".to_string());
println!("text: {}, {}, {}", original, cloned, impostor);
println!("pointers: {:p}, {:p}, {:p}", original, cloned, impostor);
text: mazurka, mazurka, mazurka
pointers: 0x55ab5c90f080, 0x55ab5c90f080, 0x55ab5c917540
assert_eq!(format!("{1},{0},{2}", "zeroth", "first", "second"),
"first,zeroth,second");
assert_eq!(format!("{2:#06x},{1:b},{0:=>10}", "first", 10, 100),
"0x0064,1010,=====first");
format!("{description:.<25}{quantity:2} @ {price:5.2}",
price=3.25,
quantity=3,
description="Maple Turmeric Latte")
"Maple Turmeric Latte..... 3 @ 3.25"
format!("{mode} {2} {} {}",
"people", "eater", "purple", mode="flying")
"flying purple people eater"
use std::fmt;
impl fmt::Display for Complex {
fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result {
let im_sign = if self.im < 0.0 { '-' } else { '+' };
write!(dest, "{} {} {}i", self.re, im_sign, f64::abs(self.im))
}
}
let one_twenty = Complex { re: -0.5, im: 0.866 };
assert_eq!(format!("{}", one_twenty),
"-0.5 + 0.866i");
let two_forty = Complex { re: -0.5, im: -0.866 };
assert_eq!(format!("{}", two_forty),
"-0.5 - 0.866i");
Fundamental-Types
There are many, many types of books in the world, which makes good sense, because there are many, many types of people, and everybody wants to read something different. —Lemony Snicke > >
Fixed-Width Numeric Types
// 10_u8.checked_mul(10).expect("数值溢出");
// 100_u8.checked_add(200).expect("");
// let x = 100_u8;
// let y = 100_u8;
// // Do the addition; panic if it overflows.
// let sum = x.checked_add(y).unwrap();
// 超出不报错
500_u16.wrapping_mul(500); // 53392
500_i16.wrapping_mul(500); // -12144
// In bitwise shift operations, the shift distance
// is wrapped to fall within the size of the value.
// So a shift of 17 bits in a 16-bit type is a shift
// of 1.
// assert_eq!(5_i16.wrapping_shl(17), 10);
Characters
assert_eq!('*' as i32, 42);
assert_eq!('ಠ' as u16, 0xca0);
assert_eq!('ಠ' as i8, -0x60); // U+0CA0 truncated to eight bits, signed
assert_eq!('*'.is_alphabetic(), false);
assert_eq!('β'.is_alphabetic(), true);
assert_eq!('8'.to_digit(10), Some(8));
assert_eq!('ಠ'.len_utf8(), 3);
assert_eq!(std::char::from_digit(2, 10), Some('2'));
Tuples
let text = "I see the eigenvalue in thine eye";
let (head, tail) = text.split_at(21);
assert_eq!(head, "I see the eigenvalue ");
assert_eq!(tail, "in thine eye");
let text = "I see the eigenvalue in thine eye";
let temp = text.split_at(21);
let head = temp.0;
let tail = temp.1;
assert_eq!(head, "I see the eigenvalue ");
assert_eq!(tail, "in thine eye");
Slices
let v: Vec<f64> = vec![0.0, 0.707, 1.0, 0.707];
let a: [f64; 4] = [0.0, -0.707, -1.0, -0.707];
let sv: &[f64] = &v;
let sa: &[f64] = &a;
Error: The variable `sv` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
[E0597] Error: `a` does not live long enough
╭─[command_23:1:1]
│
2 │ let a: [f64; 4] = [0.0, -0.707, -1.0, -0.707];
│ ┬
│ ╰── binding `a` declared here
│
4 │ let sa: &[f64] = &a;
│ ─┬
│ ╰── borrowed value does not live long enough
│ │
│ ╰── cast requires that `a` is borrowed for `'static`
───╯
String Literals
println!("In the room the women come and go,
Singing of Mount Abora");
println!("It was a bright, cold day in April, and \
there were four of us—\
more or less.");
let default_win_install_path = r"C:\Program Files\Gorillas";
println!(r###"
This raw string started with 'r###"'.
Therefore it does not end until we reach a quote mark ('"')
followed immediately by three pound signs ('###'):
"###);
In the room the women come and go,
Singing of Mount Abora
It was a bright, cold day in April, and there were four of us—more or less.
This raw string started with 'r###"'.
Therefore it does not end until we reach a quote mark ('"')
followed immediately by three pound signs ('###'):
Byte Strings
let method = b"GET";
assert_eq!(method, &[b'G', b'E', b'T']);
Strings
let noodles = "noodles".to_string();
let oodles = &noodles[1..];
let poodles = "ಠ_ಠ";
let oodles = &noodles[1..];
let oodles = &noodles[1..];
^^^^^^
The variable `oodles` contains a reference with a non-static lifetime so
can't be persisted. You can prevent this error by making sure that the
variable goes out of scope - i.e. wrapping the code in {}.
assert_eq!("ಠ_ಠ".len(), 7);
assert_eq!("ಠ_ಠ".chars().count(), 3)
()
let error_message = "too many pets".to_string();
println!("{}",error_message)
too many pets
()
format string
println!("{}",format!("{}°{:02}′{:02}″N", 24, 5, 23))
24°05′23″N
()
let bits = vec!["veni", "vidi", "vici"];
bits.concat()
"venividivici"
bits.join(",")
"veni,vidi,vici"
"ONE".to_lowercase()
"one"
"peanut".contains("nut")
true
"ಠ_ಠ".replace("ಠ", "■")
"■_■"
Iterator
// You should usually use HashSet, but its iteration order is
// nondeterministic, so BTreeSet works better in examples.
use std::collections::BTreeSet;
let mut favorites = BTreeSet::new();
favorites.insert("Lucy in the Sky With Diamonds".to_string());
favorites.insert("Liebesträume No. 3".to_string());
let mut it = favorites.into_iter();
assert_eq!(it.next(), Some("Liebesträume No. 3".to_string()));
assert_eq!(it.next(), Some("Lucy in the Sky With Diamonds".to_string()));
assert_eq!(it.next(), None);
use rand::random; // In Cargo.toml dependencies: rand = "0.7"
use std::iter::from_fn;
// Generate the lengths of 1000 random line segments whose endpoints
// are uniformly distributed across the interval [0, 1]. (This isn't a
// distribution you're going to find in the `rand_distr` crate, but
// it's easy to make yourself.)
let lengths: Vec<f64> =
from_fn(|| Some((random::<f64>() - random::<f64>()).abs()))
.take(1000)
.collect();
[E0432] Error: unresolved import `rand`
fn fibonacci() -> impl Iterator<Item = usize> {
let mut state = (0,1);
std::iter::from_fn(move || {
state = (state.1,state.0 + state.1);
Some(state.0)
})
}
assert_eq!(fibonacci().take(8).collect::<Vec<_>>(),
vec![1, 1, 2, 3, 5, 8, 13, 21])
()
drain Methods
use std::iter::FromIterator;
let mut outer = "Earth".to_string();
let inner = String::from_iter(outer.drain(1..4));
assert_eq!(outer, "Eh");
assert_eq!(inner, "art")
()
Iterator Sources
map and filter
{
let text = " ponies \n giraffes\niguanas \nsquid".to_string();
let v: Vec<&str> = text.lines()
.map(str::trim)
.collect();
assert_eq!(v, ["ponies", "giraffes", "iguanas", "squid"]);
}
()
{
let text = " ponies \n giraffes\niguanas \nsquid".to_string();
let v: Vec<&str> = text.lines()
.map(str::trim)
.filter(|s| *s != "iguanas")
.collect();
assert_eq!(v, ["ponies", "giraffes", "squid"]);
}
()
filter_map and flat_map
use std::str::FromStr;
let text = "1\nfrond .25 289\n3.1415 estuary\n";
for number in text.split_whitespace()
.filter_map(|w| f64::from_str(w).ok()){
println!("{:4.2}",number.sqrt());
}
1.00
0.50
17.00
1.77
()
use std::collections::HashMap;
let mut major_cities = HashMap::new();
major_cities.insert("Japan", vec!["Tokyo", "Kyoto"]);
major_cities.insert("The United States", vec!["Portland", "Nashville"]);
major_cities.insert("Brazil", vec!["São Paulo", "Brasília"]);
major_cities.insert("Kenya", vec!["Nairobi", "Mombasa"]);
major_cities.insert("The Netherlands", vec!["Amsterdam", "Utrecht"]);
let countries = ["Japan", "Brazil", "Kenya"];
for &city in countries.iter().flat_map(|country| &major_cities[country]) {
println!("{}", city);
}
Tokyo
Kyoto
São Paulo
Brasília
Nairobi
Mombasa
()
flatten
use std::collections::BTreeMap;
// A table mapping cities to their parks: each value is a vector.
let mut parks = BTreeMap::new();
parks.insert("Portland", vec!["Mt. Tabor Park", "Forest Park"]);
parks.insert("Kyoto", vec!["Tadasu-no-Mori Forest", "Maruyama Koen"]);
parks.insert("Nashville", vec!["Percy Warner Park", "Dragon Park"]);
use std::collections::BTreeMap;
// A table mapping cities to their parks: each value is a vector.
let mut parks = BTreeMap::new();
parks.insert("Portland", vec!["Mt. Tabor Park", "Forest Park"]);
parks.insert("Kyoto", vec!["Tadasu-no-Mori Forest", "Maruyama Koen"]);
parks.insert("Nashville", vec!["Percy Warner Park", "Dragon Park"]);
// Build a vector of all parks. `values` gives us an iterator producing
// vectors, and then `flatten` produces each vector's elements in turn.
let all_parks: Vec<_> = parks.values().flatten().cloned().collect();
assert_eq!(all_parks,
vec!["Tadasu-no-Mori Forest", "Maruyama Koen", "Percy Warner Park",
"Dragon Park", "Mt. Tabor Park", "Forest Park"]);
take and take_while
let message = "To: jimb\r\n\
From: superego <editor@oreilly.com>\r\n\
\r\n\
Did you get any writing done today?\r\n\
When will you stop wasting time plotting fractals?\r\n";
for header in message.lines().take_while(|l| !l.is_empty()) {
println!("{}" , header);
}
To: jimb
From: superego <editor@oreilly.com>
()
skip and skip_while
for body in message.lines()
.skip_while(|l| !l.is_empty())
.skip(1) {
println!("{}" , body);
}
Did you get any writing done today?
When will you stop wasting time plotting fractals?
()
peekable
use std::iter::Peekable;
fn parse_number<I>(tokens: &mut Peekable<I>) -> u32
where I:Iterator<Item = char>{
let mut n = 0;
loop {
match tokens.peek() {
Some(r) if r.is_digit(10) => {
n = n * 10 + r.to_digit(10).unwrap();
}
_ => return n
}
tokens.next();
}
}
let mut chars = "226153980,1766319049".chars().peekable();
assert_eq!(parse_number(&mut chars), 226153980);
// Look, `parse_number` didn't consume the comma! So we will.
assert_eq!(chars.next(), Some(','));
assert_eq!(parse_number(&mut chars), 1766319049);
assert_eq!(chars.next(), None);
fuse
struct Flaky(bool);
impl Iterator for Flaky {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
if self.0 {
self.0 = false;
Some("totally the last item")
} else {
self.0 = true; // D'oh!
None
}
}
}
let mut flaky = Flaky(true);
assert_eq!(flaky.next(), Some("totally the last item"));
assert_eq!(flaky.next(), None);
assert_eq!(flaky.next(), Some("totally the last item"));
let mut not_flaky = Flaky(true).fuse();
assert_eq!(not_flaky.next(), Some("totally the last item"));
assert_eq!(not_flaky.next(), None);
assert_eq!(not_flaky.next(), None);
Reversible Iterators and rev
{
let bee_parts = ["head", "thorax", "abdomen"];
let mut iter = bee_parts.iter();
assert_eq!(iter.next(), Some(&"head"));
assert_eq!(iter.next_back(), Some(&"abdomen"));
assert_eq!(iter.next(), Some(&"thorax"));
assert_eq!(iter.next_back(), None);
assert_eq!(iter.next(), None);
}
()
// fn rev(self) -> impl Iterator<Item=Self>
// where Self: Sized + DoubleEndedIterator;
{
let meals = ["breakfast", "lunch", "dinner"];
let mut iter = meals.iter().rev();
assert_eq!(iter.next(), Some(&"dinner"));
assert_eq!(iter.next(), Some(&"lunch"));
assert_eq!(iter.next(), Some(&"breakfast"));
assert_eq!(iter.next(), None);
}
()
inspect
let upper_case: String = "große".chars()
.inspect(|c| println!("before: {:?}", c))
.flat_map(|c| c.to_uppercase())
.inspect(|c| println!(" after: {:?}", c))
.collect();
assert_eq!(upper_case, "GROSSE");
before: 'g'
after: 'G'
before: 'r'
after: 'R'
before: 'o'
after: 'O'
before: 'ß'
after: 'S'
after: 'S'
before: 'e'
after: 'E'
chain
let v: Vec<i32> = (1..4).chain(vec![20, 30, 40]).collect();
assert_eq!(v, [1, 2, 3, 20, 30, 40]);
let v: Vec<i32> = (1..4).chain(vec![20, 30, 40]).rev().collect();
assert_eq!(v, [40, 30, 20, 3, 2, 1]);
enumerate
let vlist = vec!['A','B','C','D'];
for (i,c) in vlist.into_iter().enumerate() {
println!("{}--{}",i,c);
}
0--A
1--B
2--C
3--D
()
zip
let v:Vec<_> = (0..).zip("ABCD".chars()).collect();
assert_eq!(v, vec![(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D')]);
use std::iter::repeat;
let endings = vec!["once", "twice", "chicken soup with rice"];
let rhyme: Vec<_> = repeat("going")
.zip(endings)
.collect();
assert_eq!(rhyme, vec![("going", "once"),
("going", "twice"),
("going", "chicken soup with rice")]);
by_ref
let message = "To: jimb\r\n\
From: id\r\n\
\r\n\
Oooooh, donuts!!\r\n";
let mut lines = message.lines();
println!("Headers:");
for header in lines.by_ref().take_while(|l| !l.is_empty()) {
println!("{}" , header);
}
println!("\nBody:");
for body in lines {
println!("{}" , body);
}
Headers:
To: jimb
From: id
Body:
Oooooh, donuts!!
()
cloned, copied
let a = ['1', '2', '3', '∞'];
assert_eq!(a.iter().next(), Some(&'1'));
assert_eq!(a.iter().cloned().next(), Some('1'));
cycle
{
let dirs = ["North", "East", "South", "West"];
let mut spin = dirs.iter().cycle();
assert_eq!(spin.next(), Some(&"North"));
assert_eq!(spin.next(), Some(&"East"));
assert_eq!(spin.next(), Some(&"South"));
assert_eq!(spin.next(), Some(&"West"));
assert_eq!(spin.next(), Some(&"North"));
assert_eq!(spin.next(), Some(&"East"))
}
()
use std::iter::{once, repeat};
{
let fizzes = repeat("").take(2).chain(once("fizz")).cycle();
let buzzes = repeat("").take(4).chain(once("buzz")).cycle();
let fizzes_buzzes = fizzes.zip(buzzes);
let fizz_buzz = (1..100).zip(fizzes_buzzes)
.map(|tuple|
match tuple {
(i, ("", "")) => i.to_string(),
(_, (fizz, buzz)) => format!("{}{}", fizz, buzz)
});
for line in fizz_buzz {
println!("{}", line);
}
}
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
31
32
fizz
34
buzz
fizz
37
38
fizz
buzz
41
()
fizz
43
44
fizzbuzz
46
47
fizz
49
buzz
fizz
52
53
fizz
buzz
56
fizz
58
59
fizzbuzz
61
62
fizz
64
buzz
fizz
67
68
fizz
buzz
71
fizz
73
74
fizzbuzz
76
77
fizz
79
buzz
fizz
82
83
fizz
buzz
86
fizz
88
89
fizzbuzz
91
92
fizz
94
buzz
fizz
97
98
fizz
Simple Accumulation: count, sum, product
use std::cmp::Ordering;
fn cmp(lhs: &f64,rhs:&f64) -> Ordering {
lhs.partial_cmp(rhs).unwrap()
}
let numbers = [1.0, 4.0, 2.0];
assert_eq!(numbers.iter().copied().max_by(cmp), Some(4.0));
assert_eq!(numbers.iter().copied().min_by(cmp), Some(1.0));
let numbers = [1.0, 4.0, std::f64::NAN, 2.0];
assert_eq!(numbers.iter().copied().max_by(cmp), Some(4.0)); // panics
thread '<unnamed>' panicked at src/lib.rs:8:26:
called `Option::unwrap()` on a `None` value
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::panicking::panic
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:127:5
3: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
4: run_user_code_29
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
max_by_key, min_by_key
use std::collections::HashMap;
let mut populations = HashMap::new();
populations.insert("Portland", 583_776);
populations.insert("Fossil", 449);
populations.insert("Greenhorn", 2);
populations.insert("Boring", 7_762);
populations.insert("The Dalles", 15_340);
assert_eq!(populations.iter().max_by_key(|&(_name, pop)| pop),
Some((&"Portland", &583_776)));
assert_eq!(populations.iter().min_by_key(|&(_name, pop)| pop),
Some((&"Greenhorn", &2)));
Comparing Item Sequences
let packed = "Helen of Troy";
let spaced = "Helen of Troy";
let obscure = "Helen of Sandusky"; // nice person, just not famous
assert!(packed != spaced);
assert!(packed.split_whitespace().eq(spaced.split_whitespace()));
// This is true because ' ' < 'o'.
assert!(spaced < obscure);
// This is true because 'Troy' > 'Sandusky'.
assert!(spaced.split_whitespace().gt(obscure.split_whitespace()));
thread '<unnamed>' panicked at src/lib.rs:178:1:
assertion failed: packed != spaced
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::panicking::panic
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:127:5
3: <unknown>
4: <unknown>
5: evcxr::runtime::Runtime::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
any and all
let id = "Iterator";
assert!( id.chars().any(char::is_uppercase));
assert!(!id.chars().all(char::is_uppercase));
position, rposition, and ExactSizeIterator
let text = “Xerxes”; assert_eq!(text.chars().position(|c| c == ‘e’), Some(1)); assert_eq!(text.chars().position(|c| c == ‘z’), None); let bytes = b”Xerxes”; assert_eq!(bytes.iter().rposition(|&c| c == b’e’), Some(4)); assert_eq!(bytes.iter().rposition(|&c| c == b’X’), Some(0));
fold and rfold
let a = [5, 6, 7, 8, 9, 10];
assert_eq!(a.iter().fold(0, |n, _| n+1), 6); // count
assert_eq!(a.iter().fold(0, |n, i| n+i), 45); // sum
assert_eq!(a.iter().fold(1, |n, i| n*i), 151200); // produc
// max
assert_eq!(a.iter().cloned().fold(i32::min_value(), std::cmp::max),
10);
let a = ["Pack", "my", "box", "with",
"five", "dozen", "liquor", "jugs"];
// See also: the `join` method on slices, which won't
// give you that extra space at the end.
let pangram = a.iter()
.fold(String::new(), |s, w| s + w + " ");
assert_eq!(pangram, "Pack my box with five dozen liquor jugs ");
let weird_pangram = a.iter()
.rfold(String::new(), |s, w| s + w + " ");
assert_eq!(weird_pangram, "jugs liquor dozen five with box my Pack ");
try_fold and try_rfold
The nth method takes an index n, skips that many items from the iterator, and
returns the next item, or None if the sequence ends before that point. Calling .nth(0)
is equivalent to .next()
第nth方法采用索引n,从迭代器中跳过那么多项,并返回下一项,如果序列在该点之前结束,则返回无。调用. nth(0)等价于.next()
let mut squares = (0..10).map(|i| i*i);
assert_eq!(squares.nth(4), Some(16));
assert_eq!(squares.nth(0), Some(25));
assert_eq!(squares.nth(6), None);
The variable `squares` has type `std::iter::Map<std::ops::Range<i32>, impl Fn(i32) -> i32>` which cannot be persisted.
You might be able to fix this by creating a `Box<dyn YourType>`. e.g.
let v: Box<dyn core::fmt::Debug> = Box::new(foo());
Alternatively, you can prevent evcxr from attempting to persist
the variable by wrapping your code in braces.
last
let squares = (0..10).map(|i| i*i);
assert_eq!(squares.last(), Some(81));
The variable `squares` has type `std::iter::Map<std::ops::Range<i32>, impl Fn(i32) -> i32>` which cannot be persisted.
You might be able to fix this by creating a `Box<dyn YourType>`. e.g.
let v: Box<dyn core::fmt::Debug> = Box::new(foo());
Alternatively, you can prevent evcxr from attempting to persist
the variable by wrapping your code in braces.
find, rfind, and find_map
assert_eq!(populations.iter().find(|&(_name, &pop)| pop > 1_000_000),
None);
assert_eq!(populations.iter().find(|&(_name, &pop)| pop > 500_000),
Some((&"Portland", &583_776)));
let big_city_with_volcano_park = populations.iter()
.find_map(|(&city, _)| {
if let Some(park) = find_volcano_park(city, &parks) {
// find_map returns this value, so our caller knows
// *which* park we found.
return Some((city, park.name));
}
// Reject this item, and continue the search.
None
});
assert_eq!(big_city_with_volcano_park,
Some(("Portland", "Mt. Tabor Park")));
[E0425] Error: cannot find function `find_volcano_park` in this scope
╭─[command_50:1:1]
│
3 │ if let Some(park) = find_volcano_park(city, &parks) {
│ ────────┬────────
│ ╰────────── not found in this scope
───╯
Building Collections: collect and FromIterator
let args: Vec<String> = std::env::args().collect();
use std::collections::{HashSet, BTreeSet, LinkedList, HashMap, BTreeMap};
let args: HashSet<String> = std::env::args().collect();
let args: BTreeSet<String> = std::env::args().collect();
let args: LinkedList<String> = std::env::args().collect();
// Collecting a map requires (key, value) pairs, so for this example,
// zip the sequence of strings with a sequence of integers.
let args: HashMap<String, usize> = std::env::args().zip(0..).collect();
let args: BTreeMap<String, usize> = std::env::args().zip(0..).collect();
The Extend Trait
let mut v: Vec<i32> = (0..5).map(|i| 1 << i).collect();
v.extend(&[31, 57, 99, 163]);
assert_eq!(v, &[1, 2, 4, 8, 16, 31, 57, 99, 163]);
partition
let things = ["doorknob", "mushroom", "noodle", "giraffe", "grapefruit"];
// odd-numbered letter.
let (living, nonliving): (Vec<&str>, Vec<&str>)
= things.iter().partition(|name| name.as_bytes()[0] & 1 != 0);
assert_eq!(living, vec!["mushroom", "giraffe", "grapefruit"]);
assert_eq!(nonliving, vec!["doorknob", "noodle"]);
for_each and try_for_each
["doves", "hens", "birds"].iter()
.zip(["turtle", "french", "calling"].iter())
.zip(2..5)
.rev()
.map(|((item, kind), quantity)| {
format!("{} {} {}", quantity, kind, item)
})
.for_each(|gift| {
println!("You have received: {}", gift);
});
You have received: 4 calling birds
You have received: 3 french hens
You have received: 2 turtle doves
for gift in ["doves", "hens", "birds"].iter()
.zip(["turtle", "french", "calling"].iter())
.zip(2..5)
.rev()
.map(|((item, kind), quantity)| {
format!("{} {} {}", quantity, kind, item)
})
{
println!("You have received: {}", gift);
}
You have received: 4 calling birds
You have received: 3 french hens
You have received: 2 turtle doves
()
Macro
macro_rules! bad_assert_eq {
($left:expr, $right:expr) => ({
match ($left, $right) {
(left_val, right_val) => {
if !(left_val == right_val) {
panic!("assertion failed" /* ... */);
}
}
}
});
}
let s= "a rose".to_string();
bad_assert_eq!(s,"a rose");
println!("{}",s)
[E0382] Error: borrow of moved value: `s`
╭─[command_3:1:1]
│
1 │ let s= "a rose".to_string();
│ ┬
│ ╰── move occurs because `s` has type `String`, which does not implement the `Copy` trait
2 │ bad_assert_eq!(s,"a rose");
│ ┬│
│ ╰── value moved here
│ │
│ ╰─ help: consider cloning the value if the performance cost is acceptable: `.clone()`
3 │ println!("{}",s)
│ ┬
│ ╰── value borrowed here after move
───╯
println!(stringify!("hello"))
"hello"
()
println!(env!("USER"))
realcpf
()
const TEXT : &str = include_str!("/home/realcpf/Documents/rustRepos/rust-prog-2021/hello.txt");
println!("{}",TEXT);
hello world
use std::collections::HashMap;
#[derive(Clone, PartialEq, Debug)]
enum Json {
Null,
Boolean(bool),
Number(f64),
String(String),
Array(Vec<Json>),
Object(Box<HashMap<String, Json>>)
}
let students = Json::Array(vec![
Json::Object(Box::new(vec![
("name".to_string(), Json::String("Jim Blandy".to_string())),
("class_of".to_string(), Json::Number(1926.0)),
("major".to_string(), Json::String("Tibetan throat singing".to_string()))
].into_iter().collect())),
Json::Object(Box::new(vec![
("name".to_string(), Json::String("Jason Orendorff".to_string())),
("class_of".to_string(), Json::Number(1702.0)),
("major".to_string(), Json::String("Knots".to_string()))
].into_iter().collect()))
]);
macro_rules! json {
(null) => {
Json::Null
};
([ $( $element:expr ),*]) => {
Json:Array(vec![ $( $element ),*])
};
}
assert_eq!(json!(null),Json::Null)
()
let mm = json!(
[
{
"a":3.33
}
]
);
let hand_coded_value =
Json::Array(vec![
Json::Object(Box::new(vec![
("pitch".to_string(), Json::Number(440.0))
].into_iter().collect()))
]);
assert_eq!(mm,hand_coded_value)
Error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
╭─[command_15:1:1]
│
4 │ "a":3.33
│ ┬
│ ╰── expected one of `.`, `;`, `?`, `}`, or an operator
───╯
Error: path separator must be a double colon
[unused_macros] Error: unused macro definition: `bad_assert_eq`
macro_rules! json {
(null) => {
Json::Null
};
([ $( $element:tt ),* ]) => {
Json::Array(...)
};
({ $( $key:tt : $value:tt ),* }) => {
Json::Object(...)
};
($other:tt) => {
... // TODO: Return Number, String, or Boolean
};
}
macro_rules! impl_from_num_for_json {
( $( $t:ident )* ) => {
$(
impl From<$t> for Json {
fn from(n: $t) -> Json {
Json::Number(n as f64)
}
}
)*
};
}
impl_from_num_for_json!(u8 i8 u16 i16 u32 i32 u64 i64 u128 i128
usize isize f32 f64);
macro_rules! json {
(null) => {
Json::Null
};
([ $( $element:tt ),* ]) => {
Json::Array(vec![ $( json!($element) ),* ])
};
({ $( $key:tt : $value:tt ),* }) => {
Json::Object(Box::new(vec![
$( ($key.to_string(), json!($value)) ),*
].into_iter().collect()))
};
( $other:tt ) => {
Json::from($other) // Handle Boolean/number/string
};
}
let width = 4.0;
let desc =
json!({
"width": width,
"height": (width * 9.0 / 4.0)
});
[unused_macros] Error: unused macro definition: `bad_assert_eq`
[unused_macros] Error: unused macro definition: `impl_from_num_for_json`
[E0308] Error: mismatched types
╭─[command_20:1:1]
│
3 │ ╭─▶ json!({
4 │ │ "width": width,
│ │ ──┬──
│ │ ╰──── expected `Json`, found floating-point number
┆ ┆
6 │ ├─▶ });
│ │
│ ╰──────── arguments to this function are incorrect
│
│ Note: note: associated function defined here
───╯
[E0308] Error: mismatched types
╭─[command_20:1:1]
│
3 │ ╭─▶ json!({
┆ ┆
5 │ │ "height": (width * 9.0 / 4.0)
│ │ ─────────┬─────────
│ │ ╰─────────── expected `Json`, found floating-point number
6 │ ├─▶ });
│ │
│ ╰──────── arguments to this function are incorrect
│
│ Note: note: associated function defined here
───╯
Collections
// Create an empty vector
let mut numbers: Vec<i32> = vec![];
// Create a vector with given contents
let words = vec!["step", "on", "no", "pets"];
let mut buffer = vec![0u8; 1024]; // 1024 zeroed-out bytes
let lines=vec![];
let numbers = vec![];
// Get a reference to an element
let first_line = &lines[0];
// Get a copy of an element
let fifth_number = numbers[4]; // requires Copy
let second_line = lines[1].clone(); // requires Clone
// Get a reference to a slice
let my_ref = &buffer[4..12];
// Get a copy of a slice
let my_copy = buffer[4..12].to_vec(); // requires Clone
[E0282] Error: type annotations needed for `&T`
╭─[command_5:1:1]
│
4 │ let first_line = &lines[0];
│ ─────┬────│
│ ╰────── error: type annotations needed for `&T`
│ │
│ ╰─ help: consider giving `first_line` an explicit type, where the placeholders `_` are specified: `: &T`
│
7 │ let second_line = lines[1].clone(); // requires Clone
│ ────┬───
│ ╰───── type must be known at this point
───╯
let slice = [0, 1, 2, 3];
if let Some(item) = slice.first() {
println!("we got {}",item);
}
assert_eq!(slice.get(2), Some(&2));
assert_eq!(slice.get(4), None);
we got 0
let mut slice = [0, 1, 2, 3];
{
let last = slice.last_mut().unwrap();
assert_eq!(*last,3);
*last = 99;
}
assert_eq!(slice,[0,1,2,99]);
let v = [1, 2, 3, 4, 5, 6, 7, 8, 9];
assert_eq!(v.to_vec(),
vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
assert_eq!(v[0..6].to_vec(),
vec![1, 2, 3, 4, 5, 6]);
use std::collections::HashSet;
let mut byte_vec = b"Misssssssissippi".to_vec();
byte_vec.dedup();
assert_eq!(&byte_vec, b"Misisipi");
let mut byte_vec = b"Misssssssissippi".to_vec();
let mut seen = HashSet::new();
byte_vec.retain(|r| seen.insert(*r));
assert_eq!(&byte_vec, b"Misp");
assert_eq!([[1, 2], [3, 4], [5, 6]].concat(),
vec![1, 2, 3, 4, 5, 6]);
assert_eq!([[1, 2], [3, 4], [5, 6]].join(&0),
vec![1, 2, 0, 3, 4, 0, 5, 6]);
{
let v = vec![0, 1, 2, 3];
let i = 1;
let j = 2;
let a = &v[i];
let b = &v[j];
let mid = v.len() / 2;
let front_half = &v[..mid];
let back_half = &v[mid..];
}
()
{
let mut v = vec![0, 1, 2, 3];
let i = 1;
let j = 2;
let a = &mut v[i];
let b = &mut v[j]; // error: cannot borrow `v` as mutable
// more than once at a time
*a = 6; // references `a` and `b` get used here,
*b = 7; // so their lifetimes must overlap
}
[E0499] Error: cannot borrow `v` as mutable more than once at a time
╭─[command_19:1:1]
│
5 │ let a = &mut v[i];
│ ┬
│ ╰── first mutable borrow occurs here
6 │ let b = &mut v[j]; // error: cannot borrow `v` as mutable
│ ┬
│ ╰── second mutable borrow occurs here
│
8 │ *a = 6; // references `a` and `b` get used here,
│ ───┬──
│ ╰──── first borrow later used here
───╯
assert_eq!([1, 2, 3, 4].starts_with(&[1, 2]), true);
assert_eq!([1, 2, 3, 4].starts_with(&[2, 3]), false);
assert_eq!([1, 2, 3, 4].ends_with(&[3, 4]), true);
use std::collections::VecDeque;
let v = VecDeque::from(vec![1, 2, 3, 4]);
use std::collections::binary_heap::PeekMut;
use std::collections::BinaryHeap;
{
let mut heap = BinaryHeap::from(vec![2, 3, 8, 6, 9, 5, 4]);
if let Some(top) = heap.peek_mut() {
if *top > 10 {
PeekMut::pop(top);
}
}
}
[E0597] Error: `heap` does not live long enough
╭─[command_28:1:1]
│
6 │ let mut heap = BinaryHeap::from(vec![2, 3, 8, 6, 9, 5, 4]);
│ ────┬───
│ ╰───── binding `heap` declared here
7 │ if let Some(top) = heap.peek_mut() {
│ ──┬────┬───────
│ ╰────────────── borrowed value does not live long enough
│ │
│ ╰───────── a temporary with access to the borrow is created here ...
│
11 │ }
│ │
│ ╰─ help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped: `;`
│
13 │ }
│ ┬
│ ╰── `heap` dropped here while still borrowed
────╯
use std::collections::HashMap;
let mut vote_counts: HashMap<String, usize> = HashMap::new();
vote_counts.insert(String::from("a"),1);
let ballots = vec![String::from("a")];
for name in ballots {
let count = vote_counts.entry(name).or_insert(0);
*count += 1;
}
()
let s1 = "hello".to_string();
let s2 = "hello".to_string();
println!("{:p}", &s1 as &str); // 0x7f8b32060008
println!("{:p}", &s2 as &str); // 0x7f8b32060010
0x55ae0bc7af70
0x55ae0bc7e270
use std::hash::{Hash, Hasher, BuildHasher};
fn compute_hash<B, T>(builder: &B, value: &T) -> u64
where B: BuildHasher, T: Hash
{
let mut hasher = builder.build_hasher(); // 1. start the algorithm
value.hash(&mut hasher); // 2. feed it data
hasher.finish() // 3. finish, producing a u64
}
Concurrency
use std::thread;
thread::spawn(||{
let curr = thread::current();
let name = curr.name().unwrap_or("wrong").to_string();
println!("hello in thread {}",name);
})
JoinHandle { .. }
use std::{fs, thread};
use std::sync::mpsc;
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
for filename in documents {
let text = fs::read_to_string(filename)?;
if sender.send(text).is_err() {
break;
}
}
Ok(())
});
[E0425] Error: cannot find value `documents` in this scope
╭─[command_10:1:1]
│
5 │ for filename in documents {
│ ────┬────
│ ╰────── not found in this scope
───╯
use std::thread;
use std::rc::Rc;
fn main() {
let rc1 = Rc::new("ouch".to_string());
let rc2 = rc1.clone();
thread::spawn(move || { // error
rc2.clone();
});
rc1.clone();
}
Rust refuses to compile it, giving a detailed error message:
error[E0277]: `Rc<String>` cannot be sent between threads safely
--> concurrency_send_rc.rs:10:5
|
10 | thread::spawn(move || { // error
| ^^^^^ `Rc<String>` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `Rc<String>`
= note: required because it appears within the type `[closure@...]`
= note: required by `std::thread::spawn
use std::thread;
impl<T> OffThreadExt for T
where T: Iterator + Send + 'static,
T::Item: Send + 'static
{
fn off_thread(self) -> mpsc::IntoIter<Self::Item> {
// Create a channel to transfer items from the worker thread.
let (sender, receiver) = mpsc::sync_channel(1024);
// Move this iterator to a new worker thread and run it there.
thread::spawn(move || {
for item in self {
if sender.send(item).is_err() {
break;
}
}
});
// Return an iterator that pulls values from the channel.
receiver.into_iter()
}
}
[E0405] Error: cannot find trait `OffThreadExt` in this scope
╭─[command_12:1:1]
│
2 │ impl<T> OffThreadExt for T
│ ──────┬─────
│ ╰─────── not found in this scope
───╯
[E0433] Error: failed to resolve: use of undeclared crate or module `mpsc`
╭─[command_12:1:1]
│
6 │ fn off_thread(self) -> mpsc::IntoIter<Self::Item> {
│ ──┬─
│ ╰─── use of undeclared crate or module `mpsc`
│
│ Note: help: consider importing this module: `use std::sync::mpsc;
`
───╯
[E0433] Error: failed to resolve: use of undeclared crate or module `mpsc`
╭─[command_12:1:1]
│
8 │ let (sender, receiver) = mpsc::sync_channel(1024);
│ ──┬─
│ ╰─── use of undeclared crate or module `mpsc`
│
│ Note: help: consider importing this module: `use std::sync::mpsc;
`
───╯
Multiconsumer Channels Using Mutexes
pub mod shared_channel {
use std::sync::{Arc,Mutex};
use std::sync::mpsc::{channel,Sender,Receiver};
/// A thread-safe wrapper around a `Receiver`.
#[derive(Clone)]
pub struct SharedReceiver<T>(Arc<Mutex<Receiver<T>>>);
impl<T> Iterator for SharedReceiver<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let guard = self.0.lock().unwrap();
guard.recv().ok()
}
}
pub fn shared_channel<T>() -> (Sender<T>,SharedReceiver<T>) {
let (sender,receiver) = channel();
(sender,SharedReceiver(Arc::new(Mutex::new(receiver))))
}
}
Read/Write Locks (RwLock)
Condition Variables (Condvar)
Atomics
use std::sync::atomic::{AtomicIsize,Ordering};
let atom = AtomicIsize::new(0);
atom.fetch_add(1, Ordering::SeqCst);
These methods may compile to specialized machine language instructions. On the x86-64 architecture, this .fetch_add() call compiles to a lock incq instruction, where an ordinary n += 1 might compile to a plain incq instruction or any number of variations on that theme. The Rust compiler also has to forgo some optimizations around the atomic operation, since—unlike a normal load or store—it can legiti‐ mately affect or be affected by other threads right away 这些方法可以编译成专门的机器语言指令。在x86-64架构上,this.fetch_add()调用编译成锁incq指令,其中普通的n+=1可能编译成普通的incq指令或该主题的任何数量的变体。Rust编译器还必须放弃围绕原子操作的一些优化,因为与正常的加载或存储不同,它可以合法地立即影响或受到其他线程的影响
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
let cancel_flag = Arc::new(AtomicBool::new(false));
let worker_cancel_flag = cancel_flag.clone();
Traits and Generics
[A] computer scientist tends to be able to deal with nonuniform structures—case 1, case 2, case 3—while a mathematician will tend to want one unifying axiom that governs an entire system. —Donald Knuth
use std::io::Write;
fn say_hello(out: &mut dyn Write) -> std::io::Result<()> {
out.write_all(b"hello world\n")?;
out.flush()
}
use std::fs::File;
let mut local_file = File::create("hello.txt")?;
say_hello(&mut local_file)?;
let mut bytes = vec![];
say_hello(&mut bytes)?;
assert_eq!(bytes,b"hello world\n");
fn min<T: Ord>(v1: T,v2: T) -> T {
if v1 <= v2 {
v1
} else {
v2
}
}
Trait Objects
use std::io::Write;
let mut buf: Vec<u8> = vec![];
let writer: dyn Write = buf;
[E0308] Error: mismatched types
╭─[command_6:1:1]
│
4 │ let writer: dyn Write = buf;
│ ────┬──── ─┬─
│ ╰──────────── expected due to this
│ │
│ ╰─── expected `dyn Write`, found `Vec<u8>`
───╯
[E0277] Error: the size for values of type `dyn std::io::Write` cannot be known at compilation time
╭─[command_6:1:1]
│
4 │ let writer: dyn Write = buf;
│ ───┬── │
│ ╰────── doesn't have a size known at compile-time
│ │
│ ╰─ help: consider borrowing here: `&`
───╯
{
let mut buf: Vec<u8> = vec![];
let writer: &mut dyn Write = &mut buf;
}
()
内存布局
Generic Functions and Type Parameters
let v1 = (0..100).collect();
[E0282] Error: type annotations needed
╭─[command_11:1:1]
│
1 │ let v1 = (0..100).collect();
│ ─┬│
│ ╰── error: type annotations needed
│ │
│ ╰─ help: consider giving `v1` an explicit type: `: Vec<_>`
───╯
let v2 = (0..100).collect::<Vec<i32>>();
Defining and Implementing Traits
Traits and Other People’s Types
trait IsEmoji {
fn is_emoji(&self) -> bool;
}
impl IsEmoji for char {
fn is_emoji(&self) -> bool {
false
}
}
assert_eq!('$'.is_emoji(), false);
Subtraits
fn dot(v1: &[i64], v2: &[i64]) -> i64 {
let mut total = 0;
for i in 0 .. v1.len() {
total = total + v1[i] * v2[i];
}
total
}
fn dot<N>(v1: &[N], v2: &[N]) -> N {
let mut total: N = 0;
for i in 0 .. v1.len() {
total = total + v1[i] * v2[i];
}
total
}
[E0308] Error: mismatched types
╭─[command_19:1:1]
│
1 │ fn dot<N>(v1: &[N], v2: &[N]) -> N {
│ ┬
│ ╰── this type parameter
2 │ let mut total: N = 0;
│ ┬ ┬
│ ╰────── expected due to this
│ │
│ ╰── expected type parameter `N`, found integer
───╯
[E0369] Error: cannot multiply `N` by `N`
╭─[command_19:1:1]
│
1 │ fn dot<N>(v1: &[N], v2: &[N]) -> N {
│ │
│ ╰─ help: consider restricting type parameter `N`: `: std::ops::Mul`
│
4 │ total = total + v1[i] * v2[i];
│ ──┬── ┬ ──┬──
│ ╰──────────── N
│ │ │
│ ╰──────── error: cannot multiply `N` by `N`
│ │
│ ╰──── N
───╯
use std::ops::{Add, Mul};
fn dot<N: Add + Mul + Default>(v1: &[N], v2: &[N]) -> N {
let mut total = N::default();
for i in 0 .. v1.len() {
total = total + v1[i] * v2[i];
}
total
}
[E0308] Error: mismatched types
╭─[command_20:1:1]
│
2 │ fn dot<N: Add + Mul + Default>(v1: &[N], v2: &[N]) -> N {
│ ┬ │
│ ╰───────────── this type parameter
│ │
│ ╰─ help: consider further restricting this bound: `<Output = N>`
│
5 │ total = total + v1[i] * v2[i];
│ ──┬── ──────┬──────
│ ╰──────────────────── expected because this is `N`
│ │
│ ╰──────── expected type parameter `N`, found associated type
───╯
[E0308] Error: mismatched types
╭─[command_20:1:1]
│
2 │ fn dot<N: Add + Mul + Default>(v1: &[N], v2: &[N]) -> N {
│ ┬ │
│ ╰─────── this type parameter
│ │
│ ╰─ help: consider further restricting this bound: `<Output = N>`
3 │ let mut total = N::default();
│ ──────┬─────
│ ╰─────── expected due to this value
│
5 │ total = total + v1[i] * v2[i];
│ ──────────┬──────────
│ ╰──────────── expected type parameter `N`, found associated type
───╯
use std::ops::{Add, Mul};
fn dot<N>(v1: &[N], v2: &[N]) -> N
where N: Add<Output=N> + Mul<Output=N> + Default + Copy
{
let mut total = N::default();
for i in 0 .. v1.len() {
total = total + v1[i] * v2[i];
}
total
}
Operator Overloading
Operator Overloading
use std::ops::Add;
assert_eq!(4.125f32.add(5.75), 9.875);
assert_eq!(10.add(20), 10 + 20);
use std::ops::Add;
impl<T> Add for Complex<T>
where
T: Add<Output = T>,
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
Complex {
re: self.re + rhs.re,
im: self.im + rhs.im,
}
}
}
let s = "d\x6fv\x65t\x61i\x6c".to_string();
let t = "\x64o\x76e\x74a\x69l".to_string();
assert!(s == t); // s and t are only borrowed...
// ... so they still have their values here.
assert_eq!(format!("{} {}", s, t), "dovetail dovetail");
assert!("ungula" != "ungulate");
assert!("ungula".ne("ungulate"));
assert!(f64::is_nan(0.0 / 0.0));
assert_eq!(0.0 / 0.0 == 0.0 / 0.0, false);
assert_eq!(0.0 / 0.0 != 0.0 / 0.0, true);
assert_eq!(0.0 / 0.0 < 0.0 / 0.0, false);
assert_eq!(0.0 / 0.0 > 0.0 / 0.0, false);
assert_eq!(0.0 / 0.0 <= 0.0 / 0.0, false);
assert_eq!(0.0 / 0.0 >= 0.0 / 0.0, false);
#[derive(Debug, PartialEq)]
struct Interval<T> {
lower: T, // inclusive
upper: T, // exclusive
}
use std::cmp::{Ordering, PartialOrd}
impl <T: PartialOrd> PartialOrd<Interval<T>> for Interval<T> {
fn partial_cmp(&self, other: &Interval<T>) -> Option<Ordering> {
if self == other {
Some(Ordering::Equal)
} else if self.lower >= other.upper {
Some(Ordering::Greater)
} else if self.upper <= other.lower {
Some(Ordering::Less)
} else {
None
}
}
}
assert!(Interval { lower: 10, upper: 20 } < Interval { lower: 20, upper: 40 });
assert!(Interval { lower: 7, upper: 8 } >= Interval { lower: 0, upper: 1 });
assert!(Interval { lower: 7, upper: 8 } <= Interval { lower: 7, upper: 8 });
// Overlapping intervals aren't ordered with respect to each other.
let left = Interval { lower: 10, upper: 30 };
let right = Interval { lower: 20, upper: 40 };
assert!(!(left < right));
assert!(!(left >= right));
Index and IndexMut
use std::collections::HashMap;
let mut m = HashMap::new();
m.insert("十", 10);
m.insert("百", 100);
m.insert("千", 1000);
m.insert("万", 1_0000);
m.insert("億", 1_0000_0000);
assert_eq!(m["十"], 10);
assert_eq!(m["千"], 1000);
use std::ops::Index;
assert_eq!(*m.index("十"), 10);
assert_eq!(*m.index("千"), 1000);
let mut desserts =
vec!["Howalon".to_string(), "Soan papdi".to_string()];
desserts[0].push_str(" (fictional)");
desserts[1].push_str(" (real)");
use std::ops::IndexMut;
(*desserts.index_mut(0)).push_str(" (fictional)");
(*desserts.index_mut(1)).push_str(" (real)");
struct Image<P> {
width: usize,
pixels: Vec<P>,
}
impl<P: Default + Copy> Image<P> {
fn new(width: usize, height:usize) -> Image<P> {
Image { width: width, pixels: vec![P::default();width * height], }
}
}
impl<P> std::ops::Index<usize> for Image<P> {
type Output = [P];
fn index(&self, index: usize) -> &Self::Output {
let start = index * self.width;
&self.pixels[start .. start + self.width]
}
}
impl<P> std::ops::IndexMut<usize> for Image<P> {
fn index_mut(&mut self, row: usize) -> &mut [P] {
let start = row * self.width;
&mut self.pixels[start..start + self.width]
}
}
Science is nothing else than the search to discover unity in the wild variety of nature—or, more exactly, in the variety of our experience. Poetry, painting, the arts are the same search, in Coleridge’s phrase, for unity in variety. —Jacob Bronowski
Drop
struct Appellation {
name: String,
nicknames: Vec<String>
}
impl Drop for Appellation {
fn drop(&mut self) {
println!("Droping {}",&self.name);
if !&self.nicknames.is_empty() {
println!("AKA {}",&self.nicknames.join(","));
}
println!("");
}
}
{
let mut a = Appellation {
name: "Zeus".to_string(),
nicknames: vec!["cloud collector".to_string(),
"king of the gods".to_string()]
};
println!("before assignment");
a = Appellation { name: "Hera".to_string(), nicknames: vec![] };
println!("at end of block");
}
before assignment
Droping Zeus
AKA cloud collector,king of the gods
at end of block
Droping Hera
()
Sized
struct RcBox<T: ?Sized> {
ref_count: usize,
value: T,
}
use std::fmt::Display;
fn display(boxed: &RcBox<dyn Display>) {
println!("For your enjoyment: {}", &boxed.value);
}
{
let boxed_lunch: RcBox<String> = RcBox {
ref_count: 1,
value: "lunch".to_string()
};
use std::fmt::Display;
let boxed_displayable: &RcBox<dyn Display> = &boxed_lunch;
display(&boxed_lunch);
}
For your enjoyment: lunch
()
Clone
Copy
Deref and DerefMut
struct Selector<T> {
/// Elements available in this `Selector`.
elements: Vec<T>,
/// The index of the "current" element in `elements`. A `Selector`
/// behaves like a pointer to the current element.
current: usize
}
use std::ops::{Deref, DerefMut};
impl<T> Deref for Selector<T> {
type Target = T;
fn deref(&self) -> &T {
&self.elements[self.current]
}
}
impl<T> DerefMut for Selector<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.elements[self.current]
}
}
[E0119] Error: conflicting implementations of trait `DerefMut` for type `Selector<_>`
╭─[command_17:1:1]
│
1 │ impl<T> DerefMut for Selector<T> {
│ ────────────────┬───────────────
│ ╰───────────────── conflicting implementation for `Selector<_>`
───╯
let mut s = Selector { elements: vec!['x', 'y', 'z'],
current: 2 };
// Because `Selector` implements `Deref`, we can use the `*` operator to
// refer to its current element.
assert_eq!(*s, 'z');
// Assert that 'z' is alphabetic, using a method of `char` directly on a
// `Selector`, via deref coercion.
assert!(s.is_alphabetic());
// Change the 'z' to a 'w', by assigning to the `Selector`'s referent.
*s = 'w';
assert_eq!(s.elements, ['x', 'y', 'w']);
let s = Selector { elements: vec!["good", "bad", "ugly"],
current: 2 };
fn show_it(thing: &str) { println!("{}", thing); }
show_it(&s);
ugly
use std::fmt::Display;
fn show_it_generic<T: Display>(thing: T) { println!("{}", thing); }
show_it_generic(&s);
[E0277] Error: `Selector<&str>` doesn't implement `std::fmt::Display`
╭─[command_22:1:1]
│
2 │ fn show_it_generic<T: Display>(thing: T) { println!("{}", thing); }
│ ───┬───
│ ╰───── required by this bound in `show_it_generic`
3 │ show_it_generic(&s);
│ ───────┬─────── ┬
│ ╰──────────── required by a bound introduced by this call
│ │
│ ╰── `Selector<&str>` cannot be formatted with the default formatter
│ │
│ ╰── help: consider dereferencing here: `*`
───╯
show_it(&*s)
ugly
()
show_it(&s as &str)
ugly
()
Default
use std::collections::HashSet;
let squares = [4, 9, 16, 25, 36, 49, 64];
let (powers_of_two, impure): (HashSet<i32>, HashSet<i32>)
= squares.iter().partition(|&n| n & (n-1) == 0);
assert_eq!(powers_of_two.len(), 3);
assert_eq!(impure.len(), 4);
let (upper, lower): (String, String)
= "Great Teacher Onizuka".chars().partition(|&c| c.is_uppercase());
assert_eq!(upper, "GTO");
assert_eq!(lower, "reat eacher nizuka");
AsRef and AsMut
/*
What open really wants is a &Path, the type representing a filesystem path. But with
this signature, open accepts anything it can borrow a &Path from—that is, anything
that implements AsRef<Path>. Such types include String and str, the operating sys‐
tem interface string types OsString and OsStr, and of course PathBuf and Path; see
the library documentation for the full list. This is what allows you to pass string liter‐
als to open:
*/
let dot_vim = std::fs::File::open("/home/realcpf/.vim");
Borrow and BorrowMut
From and Into
use std::net::Ipv4Addr;
fn ping<A>(address: A) -> std::io::Result<bool>
where A: Into<Ipv4Addr>{
let ipv4_address = address.into();
std::io::Result::Ok(true)
}
println!("{:?}", ping(Ipv4Addr::new(23, 21, 68, 141))); // pass an Ipv4Addr
println!("{:?}", ping([66, 146, 219, 98])); // pass a [u8; 4]
println!("{:?}", ping(0xd076eb94_u32)); // pass a u32
Ok(true)
Ok(true)
Ok(true)
let addr1 = Ipv4Addr::from([66, 146, 219, 98]);
let addr2 = Ipv4Addr::from(0xd076eb94_u32);
let text = "hello world".to_string();
let bytes: Vec<u8> = text.into();
TryFrom and TryInto
let huge = 2_000_000_000_000i64;
let smaller = huge as i32;
println!("{}", smaller); // -1454759936
-1454759936
use std::convert::TryInto;
let smaller: i32 = huge.try_into().unwrap_or(i32::MAX);
let smaller: i32 = huge.try_into().unwrap_or_else(|_| {
if huge >= 0 {
i32::MAX
} else {
i32::MIN
}
});