Structs
We need to keep track of three pieces of information for each ticket:
- A title
- A description
- A status
We can start by using a String
to represent them. String is the type defined in Rust's standard library to represent
UTF-8 encoded text.
But how do we combine these three pieces of information into a single entity?
Defining a struct
A struct defines a new Rust type.
struct Ticket {
title: String,
description: String,
status: String
}
A struct is quite similar to what you would call a class or an object in other programming languages.
Defining fields
The new type is built by combining other types as fields.
Each field must have a name and a type, separated by a colon, :. If there are multiple fields, they are separated by a comma, ,.
Fields don't have to be of the same type, as you can see in the Configuration struct below:
struct Configuration {
version: u32,
active: bool
}
Instantiation
You can create an instance of a struct by specifying the values for each field:
// Syntax: <StructName> { <field_name>: <value>, ... }
let ticket = Ticket {
title: "Build a ticket system".into(),
description: "A Kanban board".into(),
status: "Open".into()
};
Accessing fields
You can access the fields of a struct using the . operator:
// Field access
let x = ticket.description;
Methods
We can attach behaviour to our structs by defining methods.
Using the Ticket struct as an example:
impl Ticket {
fn is_open(self) -> bool {
self.status == "Open"
}
}
// Syntax:
// impl <StructName> {
// fn <method_name>(<parameters>) -> <return_type> {
// // Method body
// }
// }
Methods are pretty similar to functions, with two key differences:
- methods must be defined inside an
implblock - methods may use
selfas their first parameter.selfis a keyword and represents the instance of the struct the method is being called on.
self
If a method takes self as its first parameter, it can be called using the method call syntax:
// Method call syntax: <instance>.<method_name>(<parameters>)
let is_open = ticket.is_open();
This is the same calling syntax you used to perform saturating arithmetic operations on u32 values
in the previous chapter.
Static methods
If a method doesn't take self as its first parameter, it's a static method.
struct Configuration {
version: u32,
active: bool
}
impl Configuration {
// `default` is a static method on `Configuration`
fn default() -> Configuration {
Configuration { version: 0, active: false }
}
}
The only way to call a static method is by using the function call syntax:
// Function call syntax: <StructName>::<method_name>(<parameters>)
let default_config = Configuration::default();
Equivalence
You can use the function call syntax even for methods that take self as their first parameter:
// Function call syntax:
// <StructName>::<method_name>(<instance>, <parameters>)
let is_open = Ticket::is_open(ticket);
The function call syntax makes it quite clear that ticket is being used as self, the first parameter of the method,
but it's definitely more verbose. Prefer the method call syntax when possible.
Exercise
The exercise for this section is located in 03_ticket_v1/01_struct