There are two main types of Rust custom types: structs and enumerations.

The structure of the body

Like tuples, the values in a structure can be of different data types, but the structure has its own name, and the name and type of each data in the structure must be defined, called fields.

Structures are divided into three categories:

  • C struct (C struct)
  • Tuple struct (uple struct)
  • Unit-like struct (unit-like struct)

C language style structure

Example: Definition and instantiation of a structure

// Define the User structure
// Use the 'struct' keyword to specify the structure name, and specify the field name and field type within curly braces
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,}// Create an instance of the User structure
let user1 = User {
    email: String::from("[email protected]"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1};// Change the value of the field
user1.email = String::from("[email protected]");

// Use struct update syntax to create new instances from existing instances
let user2 = User {
    email: String::from("[email protected]"),
    username: String::from("anotherusername567"),
    ..user1 // The remaining fields are the same as user1
};
Copy the code

Tuple structure

A tuple struct is a special structure that has no field name.

Example: Define a tuple structure

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

let black = Color(0.0.0);
let origin = Point(0.0.0);
Copy the code

Element structure

The unit structure does not contain any fields, and its instances do not hold data.

Example: Define a cell structure

struct Nil
Copy the code

Define methods

Methods are similar to functions: they are declared with the FN keyword and name, and can have arguments and return values. A method is associated with a structure, and its first argument is usually self (self refers to the structure instance calling the method).

Example: Define the area method of a Rectangle structure

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,}impl Rectangle {
    fn area(&self) - >u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area() // Call the area method
    );
}
Copy the code

Correlation functions

You can define functions that do not take self as an argument in an IMPL block. These are called associated functions because they are associated with structures.

Correlation functions are often used as constructors that return a new instance of a structure. For example: String::from is an associative function.

Example: Define square, the correlation function for Rectangle, a Rectangle structure

// Define an association function
impl Rectangle {
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}
// Call the correlation function
let sq = Rectangle::square(3);
Copy the code

Enumerated type

Enumerations in Rust are similar to those in C, but more powerful.

Defining enumeration types

Use the enum keyword to define enumeration types.

// Define an enumeration type that describes the IP type
enum IpAddrKind {
    V4,
    V6,
}

// Define an enumeration type describing IP addresses
enum IpAddr {
    V4(u8.u8.u8.u8), // Enumeration members can also be structs
    V6(String),}// Define an enumeration describing network events
enum WebEvent {
    // Unit structure
    PageLoad,
    PageUnload,
    // Tuple structure
    KeyPress(char),
    Paste(String),
    // Common structure
    Click { x: i64, y: i64}}Copy the code

Use enumerated

Enumerators can usually be accessed using the :: symbol.

Example:

enum SpecialPoint {
    Point(i32.i32),
    Special(String),}fn main() {
    let sp = SpecialPoint::Point(0.0);
    match sp {
        SpecialPoint::Point(x, y) => {
            println!("I'm SpecialPoint(x={}, y={})", x, y);
        }
        SpecialPoint::Special(why) => {
            println!("I'm Special because I am {}", why); }}}Copy the code

With the use declaration, you can use the members of the enumeration directly. Example:

enum Status {
    Rich,
    Poor,
}

fn main() {
    use Status::{Poor, Rich};
    // use Status::*; // This can also be used

    // 'Poor' is equivalent to 'Status::Poor'.
    let status = Poor;

    match status {
        Rich => println!("The rich have lots of money!"),
        Poor => println!("The poor have no money..."),}}Copy the code

Define methods

As with structures, methods can be defined for enumeration types in impL blocks.

Example:

enum Operations {
    Add,
    Subtract,
}

impl Operations {
    fn run(&self, x: i32, y: i32) - >i32 {
        match self {
            Self::Add => x + y,
            Self::Subtract => x - y,
        }
    }
}
Copy the code

Option<T>

Null-value functionality is available in many other languages. A Null value, “Null,” is a value that represents no value. In these languages, a variable is either a null value or a non-null value. However, such a design can easily cause errors, such as the common NullPointerException in Java, where the developer has forgotten to handle a Null variable and the compiler cannot detect it.

Tony Hoare, The inventor of Null, also said in his 2009 speech “Null References: The Billion Dollar Mistake” :

I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Rust has no null value, and it takes a different way to indicate whether there is a value or no value. It defines an enumeration type in the library: Option

. Its definition is as follows:

enum Option<T> {
    Some(T),
    None,}Copy the code

Option

is preloaded and you can use Some and None without the Option:: prefix. Some members can contain any type of data, and None represents a null value.

When using the Option

type, the compiler knows that None is possible, and it checks to see if None is handled in the code. Option

and T are different types, and Option

must be unboxed before it can be evaluated with a value of type T, which indirectly reminds developers that they must deal with None.


The relevant data

Rust Programming Language

Rust By Example

RustPrimer