Struct

The types of structs

  1. 🌟 We must specify concrete values for each of the fields in struct.
2. // Fix the error
3. struct Person {
4. name: String,
5. age: u8,
6. hobby: String
7. }
8. fn main() {
9. let age = 30;
10. let p = Person {
11. name: String::from("sunface"),
12. age,
13. };

15. println!("Success!");
16. }
  1. 🌟 Unit struct don’t have any fields. It can be useful when you need to implement a trait on some type but don’t have any data that you want to store in the type itself.
2. struct Unit;
3. trait SomeTrait {
4. // ...Some behaviors defined here.
5. }

7. // We don't care about what fields  are  in the Unit, but we care about its behaviors.
8. // So we use a struct with no fields and implement some behaviors for it
9. impl SomeTrait for Unit {  }
10. fn main() {
11. let u = Unit;
12. do_something_with_unit(u);

14. println!("Success!");
15. }

17. // Fill the blank to make the code work
18. fn do_something_with_unit(u: __) {   }
  1. 🌟🌟🌟 Tuple struct looks similar to tuples, it has added meaning the struct name provides but has no named fields. It’s useful when you want to give the whole tuple a name, but don’t care about the fields’s names.
2. // Fix the error and fill the blanks
3. struct Color(i32, i32, i32);
4. struct Point(i32, i32, i32);
5. fn main() {
6. let v = Point(__, __, __);
7. check_color(v);

9. println!("Success!");
10. }

12. fn check_color(p: Color) {
13. let (x, _, _) = p;
14. assert_eq!(x, 0);
15. assert_eq!(p.1, 127);
16. assert_eq!(__, 255);
17. }

Operating on structs

  1. 🌟 You can make a whole struct mutable when instantiating it, but Rust doesn’t allow us to mark only certain fields as mutable.
2. // Fill the blank and fix the error without adding/removing new line
3. struct Person {
4. name: String,
5. age: u8,
6. }
7. fn main() {
8. let age = 18;
9. let p = Person {
10. name: String::from("sunface"),
11. age,
12. };

14. // How can you believe sunface is only 18?
15. p.age = 30;

17. // Fill the blank
18. __ = String::from("sunfei");

20. println!("Success!");
21. }
  1. 🌟 Using field init shorthand syntax to reduce repetitions.
2. // Fill the blank
3. struct Person {
4. name: String,
5. age: u8,
6. }
7. fn main() {
8. println!("Success!");
9. }

11. fn build_person(name: String, age: u8) -> Person {
12. Person {
13. age,
14. __
15. }
16. }
  1. 🌟 You can create instance from other instance with struct update syntax
2. // Fill the blank to make the code work
3. struct User {
4. active: bool,
5. username: String,
6. email: String,
7. sign_in_count: u64,
8. }
9. fn main() {
10. let u1 = User {
11. email: String::from("[email protected]"),
12. username: String::from("sunface"),
13. active: true,
14. sign_in_count: 1,
15. };

17. let u2 = set_email(u1);

19. println!("Success!");
20. }

22. fn set_email(u: User) -> User {
23. User {
24. email: String::from("[email protected]"),
25. __
26. }
27. }
  1. 🌟🌟 We can use #[derive(Debug)] to make a struct printable.
2. // Fill the blanks to make the code work
3. #[__]
4. struct Rectangle {
5. width: u32,
6. height: u32,
7. }

9. fn main() {
10. let scale = 2;
11. let rect1 = Rectangle {
12. width: dbg!(30 * scale), // Print debug info to stderr and assign the value of  `30 * scale` to `width`
13. height: 50,
14. };

16. dbg!(&rect1); // Print debug info to stderr

18. println!(__, rect1); // Print debug info to stdout
19. }

Partial move

Within the destructuring of a single variable, both by-move and by-reference pattern bindings can be used at the same time. Doing this will result in a partial move of the variable, which means that parts of the variable will be moved while other parts stay. In such a case, the parent variable cannot be used afterwards as a whole, however the parts that are only referenced (and not moved) can still be used.

Example

2. fn main() {
3. #[derive(Debug)]
4. struct Person {
5. name: String,
6. age: Box<u8>,
7. }

9. let person = Person {
10. name: String::from("Alice"),
11. age: Box::new(20),
12. };

14. // `name` is moved out of person, but `age` is referenced
15. let Person { name, ref age } = person;

17. println!("The person's age is {}", age);

19. println!("The person's name is {}", name);

21. // Error! borrow of partially moved value: `person` partial move occurs
22. //println!("The person struct is {:?}", person);

24. // `person` cannot be used but `person.age` can be used as it is not moved
25. println!("The person's age from person struct is {}", person.age);
26. }

Exercises

  1. 🌟🌟
2. // Fix errors to make it work
3. #[derive(Debug)]
4. struct File {
5. name: String,
6. data: String,
7. }
8. fn main() {
9. let f = File {
10. name: String::from("readme.md"),
11. data: "Rust By Practice".to_string()
12. };

14. let _name = f.name;

16. // ONLY modify this line
17. println!("{}, {}, {:?}",f.name, f.data, f);
18. }

You can find the solutions here(under the solutions path), but only use it when you need it