When should we use a struct as opposed to an enum?

前端 未结 3 647
太阳男子
太阳男子 2021-02-14 08:29

Structs and enums are similar to each other.

When would it be better to use a struct as opposed to an enum (or vice-versa)? Can someone give a clear example where usin

相关标签:
3条回答
  • 2021-02-14 08:58

    Perhaps the easiest way to explain the fundamental difference is that an enum contains "variants", of which you can only ever have one at a time, whereas a struct contains one or more fields, all of which you must have.

    So you might use an enum to model something like an error code, where you can only ever have one at a time:

    enum ErrorCode {
        NoDataReceived,
        CorruptedData,
        BadResponse,
    }
    

    Enum variants can contain values if needed. For example, we could add a case to ErrorCode like so:

    enum ErrorCode {
        NoDataReceived,
        CorruptedData,
        BadResponse,
        BadHTTPCode(u16),
    }
    

    In this case, an instance of ErrorCode::BadHTTPCode always contains a u16.

    This makes each individual variant behave kind of like either a tuple struct or unit struct:

    // Unit structs have no fields
    struct UnitStruct;
    
    // Tuple structs contain anonymous values.
    struct TupleStruct(u16, &'static str);
    

    However, the advantage of writing them as enum variants is that each of the cases of ErrorCode can be stored in a value of type ErrorCode, as below (this would not be possible with unrelated structs).

    fn handle_error(error: ErrorCode) {
        match error {
            ErrorCode::NoDataReceived => println!("No data received."),
            ErrorCode::CorruptedData => println!("Data corrupted."),
            ErrorCode::BadResponse => println!("Bad response received from server."),
            ErrorCode::BadHTTPCode(code) => println!("Bad HTTP code received: {}", code)
        };
    }
    
    fn main() {
        handle_error(ErrorCode::NoDataReceived); // prints "No data received."
        handle_error(ErrorCode::BadHTTPCode(404)); // prints "Bad HTTP code received: 404"
    }
    

    You can then match on the enum to determine which variant you've been given, and perform different actions depending on which one it is.


    By contrast, the third type of struct that I didn't mention above is the most commonly used - it's the type of struct that everyone is referring to when they simply say "struct".

    struct Response {
        data: Option<Data>,
        response: HTTPResponse,
        error: String,
    }
    
    fn main() {
        let response = Response {
            data: Option::None,
            response: HTTPResponse::BadRequest,
            error: "Bad request".to_owned()
        }
    }
    

    Note that in that case, in order to create a Response, all of its fields must be given values.

    Also, the way that the value of response is created (i.e. HTTPResponse::Something) implies that HTTPResponse is an enum. It might look something like this:

    enum HTTPResponse {
        Ok,         // 200
        BadRequest, // 400
        NotFound,   // 404
    }
    
    0 讨论(0)
  • 2021-02-14 09:09

    An Enum is a type with a constrained set of values.

    enum Rainbow {
        Red,
        Orange,
        Yellow,
        Green,
        Blue,
        Indigo,
        Violet
    }
    
    let color = Red;
    
    match color {
        Red => { handle Red case },
        // all the rest would go here
    }
    

    You can store data in the Enum if you need it.

    enum ParseData {
        Whitespace,
        Token(String),
        Number(i32),
    }
    
    fn parse(input: String) -> Result<String, ParseData>;
    

    A struct is a way to represent a thing.

    struct Window {
        title: String,
        position: Position,
        visible: boolean,
    }
    

    Now you can make new Window objects that represent a window on your screen.

    0 讨论(0)
  • 2021-02-14 09:12

    Enums have multiple possibilities. Structs have only one possible "type" of thing they can be. Mathematically, we say a struct is a product type and an enum is a sum of products. If you only have one possibility, use a struct. For example, a point in space is always going to be three numbers. It's never going to be a string, or a function, or something else. So it should be a struct containing three numbers. On the other hand, if you're building a mathematical expression, it could be (for instance) a number or two expressions joined by an operator. It has multiple possibilities, so it should be an enum.

    In short, if a struct works, use a struct. Rust can optimize around it, and it's going to be clearer to anyone reading your code what the value is supposed to be treated as.

    0 讨论(0)
提交回复
热议问题