rust读书笔记

type

unit type

(), whose only possible value is an empty tuple: ()

empty type

!, cannot be instantiated, it is different from the () type, which has exactly one possible value
The main advantage of this type is that it can be cast to any other type

1
2
3
fn foo() -> ! {
panic!("This call never returns.");
}

custom type

  • struct
  1. unit struct a generic type struct
    1
    struct UnitStruct;
  2. tuple struct

    1
    struct TupleStruct(u32, u32);

  3. cpp like struct

    1
    2
    3
    4
    struct CppStruct {
    left: u32,
    right: u32,
    }

  • enum
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    //  example 1
    enum WebEvent {
    // An `enum` variant may either be `unit-like`,
    PageLoad,
    PageUnload,
    // like tuple structs,
    KeyPress(char),
    Paste(String),
    // or c-like structures.
    Click { x: i64, y: i64 },
    }

    // A function which takes a `WebEvent` enum as an argument and
    // returns nothing.
    fn inspect(event: WebEvent) {
    match event {
    WebEvent::PageLoad => println!("page loaded"),
    WebEvent::PageUnload => println!("page unloaded"),
    // Destructure `c` from inside the `enum` variant.
    WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
    WebEvent::Paste(s) => println!("pasted \"{}\".", s),
    // Destructure `Click` into `x` and `y`.
    WebEvent::Click { x, y } => {
    println!("clicked at x={}, y={}.", x, y);
    },
    }
    }


    // example 2
    // An attribute to hide warnings for unused code.
    #![allow(dead_code)]

    // enum with implicit discriminator (starts at 0)
    enum Number {
    Zero,
    One,
    Two,
    }

    // enum with explicit discriminator
    enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
    }

control flow

for

  • iterator type
  1. iter() This borrows each element of the collection through each iteration. Thus leaving the collection untouched and available for reuse after the loop.

  2. into_iter() This consumes the collection so that on each iteration the exact data is provided. Once the collection has been consumed it is no longer available for reuse as it has been 'moved' within the loop.

  3. iter_mut() This mutably borrows each element of the collection, allowing for the collection to be modified in place.

function

  1. Associated function & method
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    struct Point {
    x: f64,
    y: f64,
    }

    // Implementation block, all `Point` associated functions & methods go in here
    impl Point {
    // This is an "associated function" because this function is associated with
    // a particular type, that is, Point.
    //
    // Associated functions don't need to be called with an instance.
    // These functions are generally used like constructors.
    fn origin() -> Point {
    Point { x: 0.0, y: 0.0 }
    }

    // Another associated function, taking two arguments:
    fn new(x: f64, y: f64) -> Point {
    Point { x: x, y: y }
    }
    }

    struct Rectangle {
    p1: Point,
    p2: Point,
    }

    impl Rectangle {
    // This is a method
    // `&self` is sugar for `self: &Self`, where `Self` is the type of the
    // caller object. In this case `Self` = `Rectangle`
    fn area(&self) -> f64 {
    // `self` gives access to the struct fields via the dot operator
    let Point { x: x1, y: y1 } = self.p1;
    let Point { x: x2, y: y2 } = self.p2;

    // `abs` is a `f64` method that returns the absolute value of the
    // caller
    ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
    let Point { x: x1, y: y1 } = self.p1;
    let Point { x: x2, y: y2 } = self.p2;

    2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    // This method requires the caller object to be mutable
    // `&mut self` desugars to `self: &mut Self`
    fn translate(&mut self, x: f64, y: f64) {
    self.p1.x += x;
    self.p2.x += x;

    self.p1.y += y;
    self.p2.y += y;
    }
    }

    // `Pair` owns resources: two heap allocated integers
    struct Pair(Box<i32>, Box<i32>);

    impl Pair {
    // This method "consumes" the resources of the caller object
    // `self` desugars to `self: Self`
    fn destroy(self) {
    // Destructure `self`
    let Pair(first, second) = self;

    println!("Destroying Pair({}, {})", first, second);

    // `first` and `second` go out of scope and get freed
    }
    }

    fn main() {
    let rectangle = Rectangle {
    // Associated functions are called using double colons
    p1: Point::origin(),
    p2: Point::new(3.0, 4.0),
    };

    // Methods are called using the dot operator
    // Note that the first argument `&self` is implicitly passed, i.e.
    // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
    p1: Point::origin(),
    p2: Point::new(1.0, 1.0),
    };

    // Error! `rectangle` is immutable, but this method requires a mutable
    // object
    //rectangle.translate(1.0, 0.0);
    // TODO ^ Try uncommenting this line

    // Okay! Mutable objects can call mutable methods
    square.translate(1.0, 1.0);

    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // Error! Previous `destroy` call "consumed" `pair`
    //pair.destroy();
    // TODO ^ Try uncommenting this line
    }
  2. closure as input parameter Fn: the closure uses the captured value by reference (&T) FnMut: the closure uses the captured value by mutable reference (&mut T) FnOnce: the closure uses the captured value by value (T)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// A function which takes a closure as an argument and calls it.
// <F> denotes that F is a "Generic type parameter"
fn apply<F>(f: F) where
// The closure takes no input and returns nothing.
F: FnOnce() {
// ^ TODO: Try changing this to `Fn` or `FnMut`.

f();
}

// A function which takes a closure and returns an `i32`.
fn apply_to_3<F>(f: F) -> i32 where
// The closure takes an `i32` and returns an `i32`.
F: Fn(i32) -> i32 {

f(3)
}
  1. closure as output parameter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    fn create_fn() -> impl Fn() {
    let text = "Fn".to_owned();

    move || println!("This is a: {}", text)
    }

    fn create_fnmut() -> impl FnMut() {
    let text = "FnMut".to_owned();

    move || println!("This is a: {}", text)
    }

    fn create_fnonce() -> impl FnOnce() {
    let text = "FnOnce".to_owned();

    move || println!("This is a: {}", text)
    }

language specific

&

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
fn main() {
// Assign a reference of type `i32`. The `&` signifies there
// is a reference being assigned.
let reference = &4;

match reference {
// If `reference` is pattern matched against `&val`, it results
// in a comparison like:
// `&i32`
// `&val`
// ^ We see that if the matching `&`s are dropped, then the `i32`
// should be assigned to `val`.
&val => println!("Got a value via destructuring: {:?}", val),
}

// To avoid the `&`, you dereference before matching.
match *reference {
val => println!("Got a value via dereferencing: {:?}", val),
}

// What if you don't start with a reference? `reference` was a `&`
// because the right side was already a reference. This is not
// a reference because the right side is not one.
let _not_a_reference = 3;

// Rust provides `ref` for exactly this purpose. It modifies the
// assignment so that a reference is created for the element; this
// reference is assigned.
let ref _is_a_reference = 3;

// Accordingly, by defining 2 values without references, references
// can be retrieved via `ref` and `ref mut`.
let value = 5;
let mut mut_value = 6;

// Use `ref` keyword to create a reference.
match value {
ref r => println!("Got a reference to a value: {:?}", r),
}

// Use `ref mut` similarly.
match mut_value {
ref mut m => {
// Got a reference. Gotta dereference it before we can
// add anything to it.
*m += 10;
println!("We added 10. `mut_value`: {:?}", m);
},
}
}
  1. Dereferencing uses *
  2. Destructuring uses &, ref, and ref mut
-------------本文结束感谢您的阅读-------------