English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
In Rust, structures (Struct) and tuples (Tuple) can bundle together several types of data that are not necessarily the same into a whole. However, each member and itself in a structure has a name, so when accessing its members, it is not necessary to remember the index. Tuples are often used for non-defined multiple value passing, while structures are used for standard data structures. Each member of a structure is called a 'field'.
This is a structure definition:
struct Site { domain: String, name: String, nation: String, found: u32 }
Note: If you often use C/C++Remember that in Rust, the struct statement is only used to define and not to declare an example. There is no need for a semicolon at the end, and each field definition is separated by a comma.
Rust is influenced by JavaScript in many places, and uses the key: value syntax of JSON objects to define examples of structures:
let w3codebox = Site { domain: String::from("www.oldtoolbag.com,), name: String::from("w3codebox,), nation: String::from("China"), found: 2013 };
If you are not familiar with JSON objects, you can ignore them, just remember the format:
Struct class name { Field name : Field value, ... }
The advantage of this is not only that it makes the program more intuitive, but also that you do not need to input the values of the members in the order of definition.
If the struct being exemplified has field names that are the same as existing variable names, the writing can be simplified:
let domain = String::from("www.oldtoolbag.com); let name = String::from("w3codebox); let w3codebox = Site { domain, // is equivalent to domain : domain, name, // is equivalent to name : name, nation: String::from("China"), traffic: 2013 };
There is a situation: if you want to create an example of a struct where most of the properties need to be set to the same as an existing struct property, but only need to change the values of one or two fields, you can use the struct update syntax:
let site = Site { domain: String::from("www.oldtoolbag.com,), name: String::from("w3codebox,), ..w3codebox };
Note: ..w3Commas are not allowed after codebox. This syntax does not allow the immutable copying of another struct example, which means that you must at least redefine the value of one field to reference the values of other examples.
There is a simpler way to define and use structs:Tuple struct.
Tuple struct is a form of struct that is a tuple.
The difference from tuples is that it has named and fixed type format. Its existence is to handle those simple data that need to define types (often used) but do not want to be too complex:
struct Color(u8, u8, u8); struct Point(f64, f64); let black = Color(0, 0, 0); let origin = Point(0.0, 0.0);
"Color" and "Point coordinates" are two commonly used data types, but if you write a pair of curly braces and two names when exemplifying, it sacrifices convenience for readability, Rust does not leave this problem behind. The usage of tuple struct objects is the same as that of tuples, accessed through . and indexers:
fn main() { struct Color(u8, u8, u8); struct Point(f64, f64); let black = Color(0, 0, 0); let origin = Point(0.0, 0.0); println!("black = ({}, {}, {}),", black.0, black.1, black.2); println!("origin = ({}, {}),", origin.0, origin.1); }
Running Result:
black = (0, 0, 0) origin = (0, 0)
A struct must master the ownership of field values because when a struct is invalidated, all fields will be released.
That's why the String type is used in the examples of this chapter instead of &str.
This does not mean that there are no reference fields defined in the struct, which needs to be realized through the 'lifetimes' mechanism.
But it is still difficult to explain the concept of 'lifetimes' at this point, so it can only be explained in later chapters.
In debugging, it is very useful to display a struct instance completely. But if we manually write a format, it will be very inconvenient. So Rust provides a convenient way to output the entire struct:
[[derive(Debug)]] struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; println!("rect1 is {:?}", rect1); }
As shown in the first line: be sure to import the debugging library [[derive(Debug)]] After that, you can use the {:?} placeholder to output the entire struct in println and print macros:
rect1 is Rectangle { width: 30, height: 50 }
If there are many properties, you can use another placeholder {:#?} .
Output result:
rect1 is Rectangle { width: 30, height: 50 }
Method (Method) and function (Function) are similar, but it is used to operate struct instances.
If you have learned some object-oriented languages, you must be very clear that functions are generally placed in class definitions and represented by 'this' in the function to operate the instance.
Rust is not an object-oriented language, this can be seen from the innovation of its ownership mechanism. However, the precious thought of object-oriented can be realized in Rust.
The first parameter of a struct method must be &self, no need to declare the type, because self is not a style but a keyword.
Calculate the area of a rectangle:
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!("rect1's area is {}", rect1.area()); }
Output result:
rect1's area is 1500
Please note that you do not need to fill in 'self' when calling a struct method, which is for the sake of convenience.
An instance with multiple parameters:
struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn wider(&self, rect: &Rectangle) -> bool {}} self.width > rect.width } } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; let rect2 = Rectangle { width: 40, height: 20 }; println!("{}", rect1.wider(&rect2)); }
Running Result:
false
This program calculates rect1 Whether it is wider than rect2 Wider.
The reason why "structure method" is not called "structure function" is because the name "function" is reserved for this kind of function: it is in the impl block but does not have a &self parameter.
This function does not depend on an instance, but to use it, you need to declare it in which impl block it is.
The String::from function we have been using is a "associated function".
[[derive(Debug)]] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn create(width: u32, height: u32) -> Rectangle { Rectangle { width, height } } } fn main() { let rect = Rectangle::create(30, 50); println!("{:?}", rect); }
Running Result:
Rectangle { width: 30, height: 50 }
Tip:The structure impl block can be written multiple times, which is equivalent to concatenating their contents!
A structure can only be used as a symbol without any members:
struct UnitStruct;
We call this structure without a body a unit structure (Unit Struct).