Struct

Structs, custom data types, name associated values, and package them into meaningful combinations.

Define and instantiate

struct User {
	username: String,
    email: String,
    sign_in_count: u64,
    active: bool.// The last comma cannot be omitted
}

fn main() {
    let user1 = User { // The order of the fields need not be the same as defined, but each field must be the same
        email: String::from("[email protected]"), the username:String::from("abc"),
        active: true,
        sign_in_count: 556}; }Copy the code
// If you want to change the value of user1, you need to add the mut keyword when instantiating. All fields are mutable, not partially mutable
fn main() {
    let mut user1 = User { // The order of the fields need not be the same as defined, but each field must be the same
        email: String::from("[email protected]"), the username:String::from("abc"),
        active: true,
        sign_in_count: 556}; user.email =String::from("[email protected]");
}
Copy the code
fn build_user(email: String, username: String) -> User {
    User {
        email, // Can be short, like JS
        username,
        active: true,
        sign_in_count: 0,}}Copy the code
fn main() {
    let user1 = User {
        email: String::from("[email protected]"), the username:String::from("abc"),
        active: true,
        sign_in_count: 556};let user2 = User {
        email: String::from("[email protected]"), the username:String::from("aaa"),
        ..user1 / / to use.. Assign the same field in user1 to user2, similar to the JS extension operator
    };
}
Copy the code

Tuple struct

Define a tuple-like struct, called a tuple struct. If you want to name the entire Tuple and make it different from other tuples, you don’t need to name each element.

struct Color(i32.i32.i32);
struct Point(i32.i32.i32);

let black = Color(0.0.0);
let origin = Point(0.0.0);
// Black and origin are different types and cannot be equal
Copy the code

Unit-like Struct (no field)

You can define structs without any fields because, like “()”, the unit type gets its name. This applies to a trait that you need to implement on a type, but have no data you want to store in it.

The instance

#[derive(Debug)] // Let custom types be derived from Debug
struct Rectangle {
    width: u32,
    length: u32,}fn main() {
    let rect = Rectangle {
        width: 30,
        length: 50};println!("{}", area(&rect)); / / 1500

    println!("{:? }", rect); // Rectangle { width: 30, length: 50 }

    println!("{: #? }", rect);
    /* Rectangle { width: 30, length: 50, } */
}

fn area(rect: &Rectangle) -> u32 {
    rect.width * rect.length
}
Copy the code

The method of struct

struct Rectangle {
    width: u32,
    length: u32,}// ImpL can have more than one
impl Rectangle {
    // method, the first argument must be &self or self, called directly with "."
    fn area(&self) - >u32 {
        self.width * self.length
    }

    // The argument cannot be self. Call it with "::"
    fn square(size: u32) -> Rectangle {
        Rectangle {
            width: size,
            length: size,
        }
    }
}

fn main() {
    let rect = Rectangle {
        width: 30,
        length: 50};let s = Rectangle::square(12);

    println!("{}", rect.area());

    println!("{}", s.area());
}
Copy the code

The enumeration

Definition and Use

enum IpAddrKind {
	v4,
	v6,
}

struct IpAddr {
    kind: IpAddrKind,
    address: String,}fn main() {
    let four = IpAddrKind::v4;
    let six = IpAddrKind::v6;
    
    let home = IpAddr {
        kind: IpAddrKind::v4,
        address: String::from("127.0.0.1"),};let loopback = IpAddr {
        kind: IpAddrKind::v6,
        address: String::from(: : "1"),}; }Copy the code

To append data to a variation of an enumeration:

enum IpAddr {
    V4(String),
    V6(String),}Copy the code

Advantages: No additional structs are required, and each variant can have a different type and associated amount of data.

enum IpAddr {
    V4(u8.u8.u8.u8),
    v6(String),}fn main() {
    let home = IpAddrKind::V4(127.0.0.1);
}
Copy the code

Any type of data can be used in variants of enumerations, and enumerations can also use impL to define methods:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32.i32.i32),}impl Message {
    fn call(&self) {}}fn main() {
    let q = Message::Quit;
    let m = Message::Move { x: 20, y: 30 };
    let q = Message::Write(String::from("Hello"));
    let q = Message::ChangeColor(0.255.255);
    
    m.call();
}
Copy the code

Option to enumerate

Defined in the standard library, in Prelude, to describe situations in which a value may be present (of a type) or not.

There is no NULL in Rust, but there are enumerations of similar concepts, represented by Option

.

// It is contained in Prelude and can be used directly
enum Option<T> {
	Some(T),
	None,}Copy the code
fn main() {
    let some_number = Some(5);
    let some_string = Some("A String");
    
    let absent_number: Option<i32> = None;
    // Option
      
        can not be used directly with i32. It must be converted first to avoid null overflow
      
}
Copy the code

match

Allows a value to match a series of patterns and execute the code corresponding to the matched pattern. Patterns can be literals, variable names, wildcards…

#[derive(Debug)]
enum USState {
    Alabama,
    Alaska,
}
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(USState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => { // Multiple lines require curly braces
            println!("Penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:? }!", state);
            25}}},fn main() {
    let c = Coin::Quarter(USState::Alaska);
    println!("{}", value_in_cents(c));
}
Copy the code

Match Option < T >

fn main() {
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

fn plus_one(x: Option<i32- > >)Option<i32> {
    match x {
        None= >None.Some(i) => Some(i + 1),}}Copy the code

All possibilities must be exhausted

fn plus_one(x: Option<i32- > >)Option<i32> {
    match x {
        // None => None, // Delete this line error because not all cases are overwritten
        Some(i) => Some(i + 1),}}Copy the code

Use the wildcard _ to replace all remaining possibilities, which must come last.

fn main() {
    let v = 0u8; // There are 256 possibilities

    match v {
        1= >println!("one"),
        2= >println!("two"), _ = > (),// refer to all the remaining possibilities}}Copy the code

if let

Handles cases where only one match is concerned and the others are ignored.

/ / the match
fn main() {
    let v = 0u8; // There are 256 possibilities

    match v {
        1= >println!("one"), _ => (),}}Copy the code
// let's write
fn main() {
    let v = 0u8; // There are 256 possibilities

    if let Some(1) = v {
        println!("one"); }}Copy the code

This is equivalent to this.

Alternatively, else syntax can be used.

fn main() {
    let v = 0u8; // There are 256 possibilities

    if let Some(1) = v {
        println!("one");
    } else {
        println!("others"); }}Copy the code

Module system

Package (bag)

Cargo lets you build, test, and share Crate.

A Package contains 1 Cargo. Toml, which describes how to construct these Crates, can only contain 0-1 Library Crate, and can contain any number of Binary Crate (files are placed under SRC /bin, Each file is a separate Binary Crate), but must contain at least one Crate (either Library or binary).

Crate

A tree of modules that can produce a library or executable.

Types are binary and library.

Crate Root is the source file from which the Rust compiler starts, making up the Root Module of your Crate.

Two conventions:

  1. Rs is actually a Binary Crate’s Crate root. The current Crate name is the same as the package name.
  2. Rs is the root of library Crate. The package contains a Library Crate. The current crate name is the same as the package name.

Cargo submits the Crate root file to RUSTC to build a library or binary.

Crate’s role is to group related functionality into a scope for easy sharing between projects and preventing conflicts.

Module (Module)

Lets you control the organization, scope, and private path of your code.

In a Crate, groups the code to increase readability, ease reuse, and control the privacy of items.

Create modules using the mod keyword, support nesting.

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}}mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}}}Copy the code

Path (Path)

How to name items such as struct, function, or module.

Absolute path: Starting from Crate root, use crate name or literal

Relative path: Starting with the current module, use self, super, or the identifier of the current module

A path must consist of at least one identifier, with :: between identifiers.

// src/lib.rs
mod front_of_house {
    pub mod hosting { // Private by default
        pub fn add_to_waitlist() {}}}pub fn eat_at_restaurant() { // front_of_house and eat_at_restaurant can call each other at the same level
    crate::front_of_house::hosting::add_to_waitlist(); // Absolute path
    front_of_house::hosting::add_to_waitlist(); // Relative path
}
Copy the code
fn serve_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        super::serve_order(); // super indicates the upper path}}Copy the code

Variants in public enumerations are public, and fields under public structures are private by default.

use

Use to introduce modules.

use std::collections::HashMap;
use std::collections::HashMap as hp; // Alias can be created using as
Copy the code

Pub use Re-export

// src/lib.rs
mod front_of_house {
    pub mod hosting { // Private by default
        pub fn add_to_waitlist() {}}}use crate::front_of_house::hosting; // This module is not exposed to the outside world
pub use crate::front_of_house::hosting; // This module will be exposed to the outside world
Copy the code

Using external packages:

  1. Cargo. Toml adds dependency packages, which are downloaded from crates. IO by default
  2. Use introduces specific entries into scope
  3. The standard library (STD) is also treated as an external package, but instead of modifying cargo. Toml to include STD, use is used to introduce specific items from STD into the current scope

Use nested paths to clean up a large number of use statements:

use std::cmp::Ordering;
use std::io;
// Can be abbreviated as
use std::{cmp::Ordering, io};
Copy the code
use std::io;
use std::io::Write;
// Can be abbreviated as
use std::io::{self, Write};
Copy the code
// * is a wildcard character that can introduce all public entries in a path into scope
// Use caution
// It is used to import all the tested code into the Tests module
// Sometimes used with import (prelude) modules
use std::collections::*;
Copy the code

Commonly used collection

These collections are variable-sized data stored in heap memory.

Vector

Provided by the standard library, it can store multiple values of the same data type, and values are stored consecutively in memory.

fn main() {
	let v: Vec<i32> = Vec::new(); / / create
}
Copy the code
fn main() {
	let v = vec![1.2.3]; // Create with macros
}
Copy the code
fn main() {
	let mut v = Vec::new();
    v.push(1);
    v.push(2); / / add value
}
Copy the code
// Read the elements in veC
fn main() {
	let v = vec![1.2.3.4.5];
    let third: &i32 = &v[2]; // If index is out of bounds, the program will panic
    println!("The third element is {}", third);

    match v.get(2) {
        Some(third) => println!("The third element is {}", third),
        None= >println!("There is no third element"),}}Copy the code
// VeC traversal
fn main() {
	let v = vec![1.2.3.4.5];
    for i in &v {
        println!("{}", i); }}Copy the code
fn main() {
	let mut v = vec![1.2.3.4.5];
    for i in &mut v {
        *i += 50; / / reference solution
    }

    for i in v {
        println!("{}", i); }}Copy the code
// Implement a vector with enum to store multiple types of data
enum E {
    Int(i32),
    Float(f64),
    Text(String),}fn main() {
	let v = vec![
        E::Int(3),
        E::Text(String::from("aaa")),
        E::Float(12.43)]; }Copy the code

String

Strings are based on collections of bytes and provide methods to parse bytes into text. The core speech layer of Rust has only one string type: string slice (& STR). String slices are references to utF-8-encoded strings stored elsewhere, and string literals stored in binary are also string slices.

Strings are from the standard library, not the core language, growable, modifiable, ownable, and utF-8 encoded.

create

let mut s = String::new();
Copy the code
let data = "abcd";
let s = data.to_string();
Copy the code
let s = String::from("abcd");
Copy the code

update

fn main() {
	let mut s = String::from("foo");
    s.push_str("bar");
    println!("{}", s);
}
Copy the code
fn main() {
	let mut s = String::from("foo");
    s.push('a'); // Add a single character to String
    println!("{}", s);
}
Copy the code
fn main() {
	let s1 = String::from("foo");
    let s2 = String::from("bar");

    let s3 = s1 + &s2; // Note that s1 is no longer used
    
    println!("{}", s3);
    // println! ("{}", s1); / / complains
    // println! ("{}", s2);
}
Copy the code
fn main() {
	let s1 = String::from("foo");
    let s2 = String::from("bar");
    let s3 = String::from("abc");

    let s = format!("{} - {} - {}", s1, s2, s3);
    println!("{}", s); // foo-bar-abc
}
Copy the code

methods

fn main() {
	let len = String::from("Hola").len();

    println!("{}", len); / / 4
}
Copy the code
fn main() {
	let len = String::from("Ha ha").len();

    println!("{}", len); / / 6
}
Copy the code
fn main() {
	let w = String::from("Ha ha");

    for b in w.bytes() {
        println!("{}", b); // 229 147 136 229 147 136}}Copy the code
fn main() {
	let w = String::from("Ha ha");

    for c in w.chars() { // Unicode scalar values
        println!("{}", c); / / ha ha}}Copy the code

slice

fn main() {
	let w1 = String::from("abcde");
    let w2 = String::from("Hello?");

    let s1 = &w1[0.2];
    let s2 = &w2[0.3];
    // let s3 = &w2[0..2]; // Run an error

    println!("{}", s1); // ab
    println!("{}", s2); / / you
}
Copy the code

HashMap

HashMap<K, V> stores data as key-value pairs, one key for each value. The Hash function determines how to store K and V in memory.

Application scenario: Find data by K (any type), not by index.

Data is stored on the heap.

HashMap is used sparingly, so it’s not in Prelude, the standard library has less support for it, and there are no built-in macros to create hashMaps.

A HashMap is isomorphic; in a HashMap, all K’s must be of the same type, and all V’s must be of the same type.

create

use std::collections::HashMap;

fn main() {
	let mut scores: HashMap<String.i32> = HashMap::new();
}
Copy the code
use std::collections::HashMap;

fn main() {
	let mut scores = HashMap::new();
    scores.insert(String::from("Blue"), 10);
}
Copy the code
use std::collections::HashMap;

fn main() {
    let teams = vec![String::from("blue"), String::from("Yellow")];
    let intial_scores = vec![10.50];

    // _, _ indicates type inference based on subsequent data types
    // Zip means to pull two veCs together like a zip
	let scores: HashMap<_, _> = teams.iter().zip(intial_scores.iter()).collect();
}
Copy the code

HashMap and ownership

For types that implement Copy traits (such as I32), the value is copied into the HashMap, and for values that have ownership (such as String), the value is moved and ownership is transferred to the HashMap.

use std::collections::HashMap;

fn main() {
    let s1 = String::from("abc");
    let s2 = String::from("bcd");

    let mut map = HashMap::new();
    map.insert(s1, s2);

    println!("{}, {}", s1, s2); / / an error
}
Copy the code
use std::collections::HashMap;

fn main() {
    let s1 = String::from("abc");
    let s2 = String::from("bcd");

    let mut map = HashMap::new();
    map.insert(&s1, &s2); // Pass a reference to a value

    println!("{}, {}", s1, s2); / / is not an error
}
Copy the code

Get the value

use std::collections::HashMap;

fn main() {
    let s1 = String::from("abc");
    let s2 = String::from("bcd");

    let mut map = HashMap::new();
    map.insert(&s1, 10);
    map.insert(&s2, 50);

    let m = String::from("abc");
    let s = map.get(&m);

    match s {
        Some(s) => println!("{}", s),
        None= >println!("None"),}}Copy the code

traverse

use std::collections::HashMap;

fn main() {
    let s1 = String::from("abc");
    let s2 = String::from("bcd");

    let mut map = HashMap::new();
    map.insert(&s1, 10);
    map.insert(&s2, 50);

    for (k, v) in &map {
        println!("{}, {}", k, v); }}Copy the code

update

K already exists, corresponding to a V:

  1. Replace the existing V
  2. Keep the existing V and ignore the new V
  3. Merge the existing V with the new V

K does not exist to directly add new.

/ / 1
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(String::from("abc"), 10);
    map.insert(String::from("abc"), 50);

    println!("{:? }", map); // {"abc": 50}
}
Copy the code
/ / 2
use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert(String::from("abc"), 10);

    let e = map.entry(String::from("edf")); // entry checks whether K exists
    e.or_insert(50);

    map.entry(String::from("abc")).or_insert(30);

    println!("{:? }", map); // {"abc": 10, "edf": 50}
}
Copy the code
/ / 3
use std::collections::HashMap;

fn main() {
    let text = "hello world wonderful world";

    let mut map = HashMap::new();
    
    for word in text.split_whitespace() {
        let count = map.entry(word).or_insert(0); // return a mutable reference
        *count += 1; // Dereference and increment by 1
    }

    println!("{:? }", map); // {"hello": 1, "world": 2, "wonderful": 1}
}
Copy the code

The Hash function

By default, HashMap uses a highly encrypted Hash function that is resistant to denial of service (DoS) attacks, but it is not the fastest Hash algorithm, but it is more secure.

We can specify a different hasher to switch to another function. Hasher is the type that implements the BuildHasher trait.