struct / Field Definitions
| Since: | Rust 1.0(2015) |
|---|
A struct in Rust is a data type that groups multiple values together. There are three kinds: a regular struct with named fields, a tuple struct with unnamed fields, and a unit struct with no fields.
Syntax
// A regular struct (fields have names).
struct Point {
x: f64,
y: f64,
}
// A tuple struct (fields have no names).
struct Color(u8, u8, u8);
// A unit struct (no fields).
struct Marker;
// Creating instances.
let p = Point { x: 1.0, y: 2.5 };
let c = Color(255, 128, 0);
let m = Marker;
// Accessing fields.
println!("{}", p.x); // 1
println!("{}", c.0); // 255 (tuple structs use index access)
Struct Types
| Type | Description |
|---|---|
| struct Name { field: Type, ... } | A regular struct with named fields. |
| struct Name(Type, Type, ...); | A tuple struct with unnamed fields. |
| struct Name; | A unit struct with no fields (used as trait markers, etc.). |
| let mut s = Struct { ... } | Adding mut makes all fields mutable. |
| Field shorthand | If a variable name matches a field name, you can write { x, y } as shorthand. |
| struct S2 { .., ..s1 } | Copy remaining fields from another instance (struct update syntax). |
Sample Code
sample_struct_definition.rs
// A struct representing a sorcerer.
struct Sorcerer {
name: String,
email: String,
grade: u32,
active: bool,
}
// Tuple struct examples.
struct Point(f64, f64);
struct Meters(f64);
fn build_sorcerer(email: String, name: String) -> Sorcerer {
Sorcerer {
// Field shorthand: omit field name when variable name matches.
email,
name,
grade: 1,
active: true,
}
}
fn main() {
// Create an instance.
let user1 = Sorcerer {
name: String::from("Gojo Satoru"),
email: String::from("gojo_satoru@wp-p.info"),
grade: 1,
active: true,
};
println!("Sorcerer: {}", user1.name);
println!("Email: {}", user1.email);
println!("Grade: {}", user1.grade);
// Use mut to modify fields (the entire struct becomes mutable).
let mut user2 = build_sorcerer(
String::from("ryomen_sukuna@wp-p.info"),
String::from("Ryomen Sukuna"),
);
user2.grade = 0;
println!("Ryomen Sukuna's updated grade: {}", user2.grade);
// Struct update syntax: create a new instance changing only some fields.
let user3 = Sorcerer {
email: String::from("itadori_yuji@wp-p.info"),
name: String::from("Itadori Yuji"),
..user1 // Copy remaining fields from user1.
};
println!("user3 grade: {}", user3.grade); // 1 (copied from user1)
println!("user3 active: {}", user3.active); // true
// Using tuple structs.
let p = Point(3.0, 4.0);
let d = Meters(5.2);
println!("Point: ({}, {})", p.0, p.1);
println!("Distance: {} m", d.0);
// Tuple structs support destructuring.
let Point(x, y) = p;
println!("x={}, y={}", x, y);
}
Compile with the following command:
rustc struct_definition.rs ./struct_definition Sorcerer: Gojo Satoru Email: gojo_satoru@wp-p.info Grade: 1 Ryomen Sukuna's updated grade: 0 user3 grade: 1 user3 active: true Point: (3, 4) Distance: 5.2 m x=3, y=4
Common Mistakes
Mistake 1: Ownership of a String field is moved by the struct update syntax
When a String field is copied via the update syntax (..other), String does not implement Copy, so ownership is moved to the new instance. After the move, that field on the original instance can no longer be accessed.
struct_def_mistake1.rs
#[derive(Debug)]
struct Sorcerer {
name: String,
grade: u32,
}
fn main() {
let s1 = Sorcerer {
name: String::from("Gojo Satoru"),
grade: 1,
};
let s2 = Sorcerer {
grade: 0,
..s1 // Ownership of s1.name is moved into s2.
};
println!("s2: {:?}", s2);
// s1.name can no longer be used.
// println!("{}", s1.name); // compile error
// grade is Copy, so s1.grade is still accessible.
println!("s1.grade: {}", s1.grade);
}
Compile with the following command:
rustc struct_def_mistake1.rs
./struct_def_mistake1
s2: Sorcerer { name: "Gojo Satoru", grade: 0 }
s1.grade: 1
To keep the original instance alive, call clone() before using the update syntax.
struct_def_fix1.rs
#[derive(Debug, Clone)]
struct Sorcerer {
name: String,
grade: u32,
}
fn main() {
let s1 = Sorcerer {
name: String::from("Gojo Satoru"),
grade: 1,
};
let s2 = Sorcerer {
grade: 0,
..s1.clone() // Clone s1 so that s1.name is copied, not moved.
};
// Both s1 and s2 are usable.
println!("s1: {:?}", s1);
println!("s2: {:?}", s2);
}
Compile with the following command:
rustc struct_def_fix1.rs
./struct_def_fix1
s1: Sorcerer { name: "Gojo Satoru", grade: 1 }
s2: Sorcerer { name: "Gojo Satoru", grade: 0 }
Mistake 2: Forgetting mut makes fields immutable
In Rust, modifying a struct instance requires declaring the variable as mut. You cannot make individual fields mutable — the entire struct becomes mutable when mut is used.
struct_def_mistake2.rs
struct Point {
x: f64,
y: f64,
}
fn main() {
let p = Point { x: 1.0, y: 2.0 }; // no mut
// Attempting to modify a field causes an error.
p.x = 3.0; // compile error: cannot assign to `p.x`, as `p` is not declared as mutable
}
Compile with the following command:
rustc struct_def_mistake2.rs error[E0594]: cannot assign to `p.x`, as `p` is not declared as mutable
Add mut to the variable declaration.
struct_def_fix2.rs
struct Point {
x: f64,
y: f64,
}
fn main() {
let mut p = Point { x: 1.0, y: 2.0 }; // add mut
p.x = 3.0;
p.y = 4.0;
println!("({}, {})", p.x, p.y); // (3, 4)
}
Compile with the following command:
rustc struct_def_fix2.rs ./struct_def_fix2 (3, 4)
Overview
Rust structs do not implement traits like Debug by default. To enable println!("{:?}", s) debug output, you need to add the #[derive(Debug)] attribute.
With the struct update syntax (..other), fields of types like String have their ownership moved. After the move, those fields on the original instance can no longer be accessed.
For adding methods to a struct, see impl / method definitions. For automatic trait implementations, see #[derive(Debug, Clone, PartialEq)].
If you find any errors or copyright issues, please contact us.