SoFunction
Updated on 2025-04-05

Analysis of the reason why you want to organize data with Struct and Enum in Rust

Why do you need to organize data with Struct and Enum in Rust?

Rust is a system programming language that focuses on memory security and efficiency. Its design philosophy of type systems emphasizesClarityandSecuritystruct(Structure) andenum(Enum) is the core tool for organizing data in Rust. They not only make the code more readable, but also avoid runtime errors through static checks of the compiler. This article will explore in-depth why it is necessary to use it in Rust through specific examplesstructandenumto manage data.

1. Use struct to organize data: bind related fields together

Scenario: Manage user information

Assume that user data needs to be processed, includingusernameageandMail. If not usedstruct, the code may be as follows:

// Code without structfn print_user(name: String, age: u8, email: String) {
    println!("user: {}, age: {}, Mail: {}", name, age, email);
}
fn main() {
    let name = String::from("Zhang San");
    let age = 25;
    let email = String::from("zhangsan@");
    // Problem: The parameter order is prone to errors!    print_user(email, age, name); // Error: Email and username are transmitted inversely}

question

  • The order of parameters is easily confused (for example,emailandname).
  • All relevant function signatures need to be modified when adding a new field.
  • The data is scattered and lacks logical correlation.

Optimization with struct

passstructBind the relevant fields into a whole:

struct User {
    name: String,
    age: u8,
    email: String,
}
fn print_user(user: &User) {
    println!(
        "user: {}, age: {}, Mail: {}",
        , , 
    );
}
fn main() {
    let user = User {
        name: String::from("Zhang San"),
        age: 25,
        email: String::from("zhangsan@"),
    };
    print_user(&user); // Correct: fields are clearly associated through structure}

Advantages

  • Centralized data management: All fields are encapsulated in a logical unit.
  • Avoid parameter errors: Just pass a structure reference.
  • Scalability: When adding a new field, just modify the structure definition.

2. Use enum to process diversity: express different data variants

Scenario: Process different types of messages

Suppose you need to process different message types (text, pictures, videos) from the network. If not usedenum, may need to usestructCouple tag fields:

// Enum code not usedstruct Message {
    kind: String,  // Mark the type with string: "text", "image", "video"    content: String,
}
fn process_message(msg: &Message) {
    if  == "text" {
        println!("Text received: {}", );
    } else if  == "image" {
        println!("Received pictures: {}", );
    } else {
        // Potential problem: Some types may be missed!        panic!("Unknown message type");
    }
}

question

  • Type tags are prone to misspellings (e.g."image"Written"img")。
  • Need to manually handle unknown types.
  • The compiler cannot check whether all branches are overwritten.

useenumoptimization

passenumDefinitely define all possible variants:

enum Message {
    Text(String),
    Image { url: String, width: u32, height: u32 },
    Video(String),
}
fn process_message(msg: &Message) {
    match msg {
        Message::Text(text) => println!("Text received: {}", text),
        Message::Image { url, width, height } => {
            println!("Received pictures: {} (size: {}x{})", url, width, height)
        }
        Message::Video(url) => println!("Received video: {}", url),
    }
}
fn main() {
    let msg1 = Message::Text(String::from("Hello!"));
    let msg2 = Message::Image {
        url: String::from("/"),
        width: 800,
        height: 600,
    };
    process_message(&msg1);
    process_message(&msg2);
}

Output

Text received: Hello!
Image received: / (Size: 800x600)

Advantages

  • Type safety: All possible message types are clearly defined.
  • Pattern matchingmatchExpressions force all cases.
  • Data Relevance: Each variant can carry different data (e.g.ImageIncludes dimensions).

3. The combination of struct and enum: implementing complex logic

Scenario: parsing network packets

Suppose you need to parse two packets:Login(Including username and password) andLogout(Includes timestamps only). By combiningenumandstruct, can clearly express the data:

// Define the packet typeenum Packet {
    Login(LoginData),
    Logout(LogoutData),
}
// The data structure of the login packagestruct LoginData {
    username: String,
    password: String,
}
// Log out the data structure of the packagestruct LogoutData {
    timestamp: u64,
}
fn parse_packet(packet: Packet) {
    match packet {
        Packet::Login(data) => {
            println!(
                "Login Request - username: {}, password: {}",
                , 
            )
        }
        Packet::Logout(data) => {
            println!("Logout time: {}", )
        }
    }
}
fn main() {
    let login_packet = Packet::Login(LoginData {
        username: String::from("user123"),
        password: String::from("secret"),
    });
    let logout_packet = Packet::Logout(LogoutData {
        timestamp: 1629782400,
    });
    parse_packet(login_packet);
    parse_packet(logout_packet);
}

Output

Login request - Username: user123, Password: secret
Logout time: 1629782400

Design Highlights

  • Layered abstractionenumDefine the package type,structDefine the specific data format.
  • Extensibility: Just expand when adding a new package typeenum, no need to modify the parsing logic.

4. Pattern matching: Ensure logical integrity

Rust'smatchExpressions in withenumWhen combined, the developer is forced to handle all possible situations. For example, if we are inMessageAdded one to the enumerationAudioVariations:

enum Message {
    Text(String),
    Image { url: String, width: u32, height: u32 },
    Video(String),
    Audio(String), // Added variant}
fn process_message(msg: &Message) {
    match msg {
        Message::Text(text) => println!("Text received: {}", text),
        Message::Image { url, width, height } => {
            println!("Received pictures: {} (size: {}x{})", url, width, height)
        }
        // The compiler will report an error: The `Message::Audio` branch is not processed!    }
}

At this time, the compiler will directly report an error, indicating that it is not processedAudiotype, thus avoiding runtime missed logic.

5. Comparison with object-oriented programming

In traditional object-oriented languages ​​such as Java, similar functions may be implemented through classes and inheritance. But Rust passedstructandenumA lighter and safer solution is provided:

// Define a "shape" enumenum Shape {
    Circle { radius: f64 },
    Rectangle { width: f64, height: f64 },
}
// Implement methods for enumerationimpl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
            Shape::Rectangle { width, height } => width * height,
        }
    }
}
fn main() {
    let circle = Shape::Circle { radius: 3.0 };
    let rect = Shape::Rectangle {
        width: 4.0,
        height: 5.0,
    };
    println!("Circular area: {:.2}", ()); // Output: 28.27    println!("Rectangle area: {:.2}", ());   // Output: 20.00}

Key Difference

  • No inheritance: Rust encourages combination rather than inheritance, avoiding problems such as diamond inheritance.
  • Zero cost abstractionenumandstructThere is no extra overhead at runtime.

Summary: Why must be usedstructandenum

  • Logical clarity
    • passstructEncapsulate the relevant data into a single entity, throughenumClearly define all possible states.
  • Memory security
    • The Rust compiler ensures that the data is always valid through ownership and lifecycle checks.
  • Pattern matching completeness
    • Force all possibleenumVariants, avoid logical omissions.
  • high performance
    • structandenumCompact layout in memory with no additional runtime overhead.
  • Maintainability
    • When adding new features, just expandenumorstruct, without the need to refactor the code at scale.

By reasonable usestructandenum, developers can write Rust code that is both safe and efficient, which is one of the key reasons why Rust can stand out in the fields of system programming, embedded development, etc.

Here is the article about why you need to organize data using Struct and Enum in Rust? That’s all for the article. For more information about Rust Struct and Enum organization data, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!