Skip to content

Programming Rust 2nd Edition-2021

Published: at 19:22

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 image.png > image.png > image.png

Fixed-Width Numeric Types

image.png image.png

// 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);

image.png image.png

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`
───╯

image.png

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 {}.

image.png

assert_eq!("ಠ_ಠ".len(), 7);
assert_eq!("ಠ_ಠ".chars().count(), 3)
()

image.png

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)");
}
()

image.png

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
()

image.png

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
───╯

image.png

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

image.png

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;

image.png

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();

image.png

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;`
───╯

image.png

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 {}.

image.png

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);
}
()

image.png

Comparing References

{
    let x = 10;
let y = 10;
let rx = &x;
let ry = &y;
let rrx = &rx;
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
───╯

image.png image.png image.png

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(&parabola);
}
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(&parabola);
   │              ────┬────
   │                  ╰────── 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(&parabola);
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 {}.

image.png

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
───╯

image.png image.png

Taking Arms Against a Sea of Objects

image.png

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 内存布局

image.png

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

image.png

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()),
 }
}

image.png

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) }
}
}

image.png image.png

// 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 image.png > image.png > image.png

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

image.png

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) {
...
}
...
}

image.png image.png image.png

bin

image.png

Attributes

image.png image.png

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

image.png

Package Versions

image.png

Input and Output

image.png

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;
        }
    }

image.png

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
───╯

image.png

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("/")])
()

image.png image.png

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

image.png

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('カ'))
()

image.png image.png image.png

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

image.png

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");

image.png

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

image.png

assert_eq!(format!("{{a, c}} ⊂ {{a, b, c}}"),
"{a, c} ⊂ {a, b, c}");

Formatting Text Values

image.png

assert_eq!(format!("{:4}", "th\u{e9}"), "th\u{e9} ");
assert_eq!(format!("{:4}", "the\u{301}"), "the\u{301}");

Formatting Numbers

image.png image.png

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"

image.png

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 image.png > image.png > image.png

Fixed-Width Numeric Types

image.png image.png

// 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);

image.png image.png

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`
───╯

image.png

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 {}.

image.png

assert_eq!("ಠ_ಠ".len(), 7);
assert_eq!("ಠ_ಠ".chars().count(), 3)
()

image.png

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

image.png image.png

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

image.png

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
───╯

image.png

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`

image.png

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

image.png

// 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

image.png

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
───╯

image.png image.png

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

image.png image.png

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))))
    }
}

image.png

Read/Write Locks (RwLock)

image.png

Condition Variables (Condvar)

image.png

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
    }
}

image.png

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;
}
()

内存布局

image.png

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>>();

image.png

Defining and Implementing Traits

image.png image.png image.png

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

image.png

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

image.png

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,
}
}
}

image.png image.png image.png

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);

image.png

#[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 image.png

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

image.png

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

image.png

Copy

image.png

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
    }
});