* Render the book in PDF using `pandoc` and LaTeX. * Fix installs. * Go the apt-get route * Another attempt * Avoid installing twice. * Re-order. * Add more packages. * Minimise deps. Fix link checker. * Missing package. * Missing package. * Missing package. * More packages. * Missing package. * Missing package. * More packages... * Remove. * Fix link checker. * Fix link checker. * Fix path. * Add subtitle. * Avoid running over the right margin. * Avoid running over the right margin. * Formatting
3.5 KiB
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.