Step 1 of 7 · Reading · ~3 min
Learn
Structs, Enums, and Error Handling
Structs
A struct bundles several related values into one named type of your own. By the end of this lesson you can define a struct, build instances of it, and write methods that read the fields of the value they are called on and of a second value passed in.
Defining a struct and building an instance
Each value inside a struct is a field, and each field has a name and a type. A value built from the struct is an instance.
struct Span {
start: i32,
end: i32,
}
fn main() {
let morning = Span { start: 9, end: 12 };
println!("{} to {}", morning.start, morning.end); // 9 to 12
}
You must give every field a value when you build an instance, in any order, and you read a field with a dot: morning.end is 12. Fields of type i32 are Copy, so reading them never moves anything.
Methods live in an impl block
A method is a function attached to a struct. You write it inside impl Span { ... }, and its first parameter is the receiver, the instance the method was called on:
&selfborrows the instance read-only (the common case),&mut selfborrows it so the method can change fields,selftakes ownership and consumes it.
Inside the method, self.start is the field of the instance you called it on.
impl Span {
fn length(&self) -> i32 {
self.end - self.start
}
fn gap_until(&self, later: &Span) -> i32 {
later.start - self.end
}
}
let morning = Span { start: 9, end: 12 };
let evening = Span { start: 17, end: 20 };
println!("{}", morning.length()); // 3
println!("{}", morning.gap_until(&evening)); // 5
morning.gap_until(&evening) runs with self = morning and later = evening. Trace it: later.start is 17, self.end is 12, so the result is 5. The second instance is passed as &Span, a borrow, exactly as the ownership lesson borrowed a String; the caller keeps evening.
The trap is reading a field from the wrong instance, or the wrong field. self.start - later.end compiles just as happily and prints -11. The compiler checks types, not meaning: both fields are i32, so any mix-up is legal code with a wrong answer.
Associated functions
A function in an impl block with no receiver is an associated function. You call it on the type with ::, and it is the usual way to write a constructor:
impl Span {
fn hour_at(start: i32) -> Span {
Span { start: start, end: start + 1 }
}
}
let lunch = Span::hour_at(13); // start 13, end 14
Tuple structs, update syntax, derive
- A tuple struct has no field names:
struct Rgb(u8, u8, u8);builds withRgb(255, 0, 0)and reads with.0,.1,.2. - Struct update syntax copies the remaining fields from another instance:
Span { end: 18, ..evening }takesstartfromevening. Non-Copy fields such as aStringare moved out of it. #[derive(Debug)]above the struct letsprintln!("{:?}", morning)printSpan { start: 9, end: 12 }. Without it,{:?}does not compile.
Common mistakes
- Mixing up x and y. Subtracting a
yfield from anxfield compiles because both arei32. For points (1, 5) and (4, 9) that prints65instead of25. - Squaring only one axis. For (3, 7) and (3, 2) it prints
-5instead of25. - Squaring the sum of the differences. For (2, 3) and (5, -1) the differences are 3 and -4; their sum squared is
1, but the correct answer is25. - Taking the square root. The task asks for the squared distance: (0, 0) to (3, 4) is
25, not5.
Your exercise
Fill in the distance_sq method on Point. The starter already defines the struct, reads the four numbers, builds the two points and prints the method's result; only the method body is yours. Use self for the first point and other for the second, and keep each axis on its own.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…