- Core Concepts
- Ownership
- Borrowing
- Lifetimes
- Enums
- Handling Errors
- Iterator
- Advanced Lifetimes
- Generics
- Traits
- Every value is "owned" by a single variable, struct, vector, etc. at a time.
- Reassigning the value to another variable, passing it to a function, or putting it into a vector moves the value. The old variable can't be used anymore!
#[derive(Debug)]
struct Student {
id: u32,
name: String,
score: i32,
}
impl Student {
// Associated fn to create new student
fn new_student(id: u32, name: String) -> Self {
Student {
id: id,
name: name,
score: 0,
}
}
}
#[derive(Debug)]
struct School {
students: Vec<Student>,
}
impl School {
// Associated fn to create new school
fn new_school() -> Self {
School {students: vec![]}
}
}
Example #1
fn print_student (student: Student) {
println!("{:#?}", student);
}
fn main() {
let school = School::new_school();
let other_school = school;
println!("{:#?}", school);
}
error[E0382]: borrow of moved value: `school`
--> src/test.rs:53:23
|
51 | let school = School::new_school();
| ------ move occurs because `school` has type `School`, which does not implement the `Copy` trait
52 | let other_school = school;
| ------ value moved here
53 | println!("{:#?}", school);
| ^^^^^^ value borrowed here after move
|
Example #2
fn print_student (student: Student) {
println!("{:#?}", student);
}
fn main() {
let new_student = Student::new_student(7, String::from("Joe"));
print_student(new_student);
print_student(new_student);
}
error[E0382]: use of moved value: `new_student`
--> src/test.rs:53:19
|
51 | let new_student = Student::new_student(7, String::from("Joe"));
| ----------- move occurs because `new_student` has type `Student`, which does not implement the `Copy` trait
52 | print_student(new_student);
| ----------- value moved here
53 | print_student(new_student);
| ^^^^^^^^^^^ value used here after move
|
Example #3
fn print_student (student: Student) {
println!("{:#?}", student);
}
fn main() {
let student = Student::new_student(7, String::from("Joe"));
let list_of_students = vec![student];
print_student(student);
}
error[E0382]: use of moved value: `student`
--> src/test.rs:53:19
|
51 | let student = Student::new_student(7, String::from("Joe"));
| ------- move occurs because `student` has type `Student`, which does not implement the `Copy` trait
52 | let list_of_students = vec![student];
| ------- value moved here
53 | print_student(student);
| ^^^^^^^ value used here after move
|
Example #4
fn main() {
let school = School::new_school();
let students = school.students;
println!("{:#?}", school.students);
}
error[E0382]: borrow of moved value: `school.students`
--> src/test.rs:53:23
|
52 | let students = school.students;
| --------------- value moved here
53 | println!("{:#?}", school.students);
| ^^^^^^^^^^^^^^^ value borrowed here after move
Example #5
fn print_student (student: Student) {
println!("{:#?}", student);
}
fn main() {
let student = Student::new_student(7, String::from("Joe"));
print_student(student);
println!("{:#?}", student.name);
}
error[E0382]: borrow of moved value: `student`
--> src/test.rs:54:23
|
52 | let student = Student::new_student(7, String::from("Joe"));
| ------- move occurs because `student` has type `Student`, which does not implement the `Copy` trait
53 | print_student(student);
| ------- value moved here
54 | println!("{:#?}", student.name);
| ^^^^^^^^^^^^ value borrowed here after move
Example #6
fn print_student (student: Student) {
println!("{:#?}", student);
}
fn print_name(name: String) {
println!("{:#?}", name);
}
fn main() {
let student = Student::new_student(7, String::from("Joe"));
print_name(student.name);
print_student(student);
}
error[E0382]: use of partially moved value: `student`
--> src/test.rs:54:19
|
53 | print_name(student.name);
| ------------ value partially moved here
54 | print_student(student);
| ^^^^^^^ value used here after partial move
|
= note: partial move occurs because `student.name` has type `String`, which does not implement the `Copy` trait
fn print_student(student: Student) -> Student {
println!("{:#?}", student);
student //implicit return
}
fn main() {
let mut student = Student::new_student(7, String::from("Joe"));
student = print_student(student);
student = print_student(student);
println!("{:?}", student);
}
- You can create many read-only references to a value that exist at the same time.
- You can't move a value while a reference to the value exists.
fn print_student(student: &Student) {
println!("{:#?}", student);
}
fn main() {
let student = Student::new_student(7, String::from("Joe"));
print_student(&student);
println!("{:?}", student);
}
Here, we see the & operator being used on a type. This means the arguments needs to be a reference to a value.
fn print_student(student: &Student) {
& operator being used on an owner of a value. this mens we wil create a reference to this value.
print_student(&student);
Rule no 4.
fn print_student(student: &Student) {
println!("{:#?}", student);
}
fn main() {
let student = Student::new_student(7, String::from("Joe"));
print_student(&student); // First immutable borrow
print_student(&student); // Second immutable borrow
let other_student = student; // Ownership of 'student' is moved to 'other_student'
println!("{:?}", student); // Error: 'student' has been moved and can no longer be used
}
error[E0382]: borrow of moved value: `student`
--> src/test.rs:63:22
|
57 | let student = Student::new_student(7, String::from("Joe"));
| ------- move occurs because `student` has type `Student`, which does not implement the `Copy` trait
...
62 | let other_student = student;
| ------- value moved here
63 | println!("{:?}", student);
| ^^^^^^^ value borrowed here after move
|
- You can make a writable (mutable) reference to a value only if there are no read-only references currently in use. One mutable reference to a value can exist at a time.
- You can't mutate a value through the owner when any reference (mutable or immutable) to the value exists.
- Some types of values are copied instead of moved (numbers, booleans, characters, arrays/tuples with copyable elements).
fn change_score (student: &mut Student) {
student.score = 100;
}
fn main() {
let mut student = Student::new_student(7, String::from("Joe"));
change_score(&mut student);
println!("{:#?}", student);
}
Not to do:
fn change_score (student: &mut Student) {
student.score = 100;
}
fn main() {
let mut student = Student::new_student(7, String::from("Joe"));
let student_ref = &student;
change_score(&mut student);
println!("{:#?}", student_ref.name);
}
error[E0502]: cannot borrow `student` as mutable because it is also borrowed as immutable
--> src/test.rs:49:18
|
48 | let student_ref = &student;
| -------- immutable borrow occurs here
49 | change_score(&mut student);
| ^^^^^^^^^^^^ mutable borrow occurs here
50 | println!("{:#?}", student_ref.name);
| ---------------- immutable borrow later used here
fn change_score (student: &mut Student) {
student.score = 100;
}
fn main() {
let mut student = Student::new_student(7, String::from("Joe"));
let student_ref = &mut student;
change_score(&mut student);
println!("{:#?}", student_ref.name);
}
error[E0499]: cannot borrow `student` as mutable more than once at a time
--> src/test.rs:49:18
|
48 | let student_ref = &mut student;
| ------------ first mutable borrow occurs here
49 | change_score(&mut student);
| ^^^^^^^^^^^^ second mutable borrow occurs here
50 | println!("{:#?}", student_ref.name);
| ---------------- first borrow later used here
fn change_score (student: &mut Student) {
student.score = 100;
}
fn main() {
let mut student = Student::new_student(7, String::from("Joe"));
let student_ref = &mut student;
student.score = 100;
change_score(student_ref);
println!("{:#?}", student);
}
error[E0506]: cannot assign to `student.score` because it is borrowed
--> src/test.rs:49:5
|
48 | let student_ref = &mut student;
| ------------ `student.score` is borrowed here
49 | student.score = 100;
| ^^^^^^^^^^^^^^^^^^^ `student.score` is assigned to here but it was already borrowed
50 | change_score(student_ref);
| ----------- borrow later used here
To do:
fn add_student(school: &mut School, student: Student) {
school.students.push(student);
}
fn main() {
let mut school = School::new_school();
let student = Student::new_student(7, String::from("Joe"));
add_student(&mut school, student);
println!("{:#?}", school);
println!("{:#?}", school.students[0]); // print 'student' value
}
School {
students: [
Student {
id: 7,
name: "Joe",
score: 0,
},
],
}
Student {
id: 7,
name: "Joe",
score: 0,
}
- When a variable goes out of scope, the value owned by it is dropped (cleaned up in memory).
- Values can't be dropped if there are still active references to them.
- References to a value can't outlive the value they refer to.
fn print_score(student: &Student) {
println!("{}", student.score);
}
fn main() {
let mut school = School::new_school();
let student = Student::new_student(1, String::from("me"));
let student_ref = &student; // Immutable reference to 'account'
school.students.push(student); // Error: 'student' is moved here
print_score(student_ref); // Error: Cannot use 'student_ref' after 'student' has been moved
}
fn print_score(student: &Student) {
println!("{}", student.score);
}
fn main() {
let mut school = School::new_school();
let student = Student::new_student(1, String::from("me"));
let student_ref = &student; // Immutable reference to 'student'
print_score(student_ref); // Borrowing 'student' as immutable for printing its score
school.students.push(student); // 'student' is moved into 'school.accounts'
}
Storing a value --> Take ownership (receive a value) Calculation with a value --> Read-only ref (&) Change a value --> Mutable Ref (&mut)
https://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-introduction/ https://www.figma.com/blog/rust-in-production-at-figma/ https://www.rykap.com/2020/09/23/distance-fields/