03-Exercise Mediainfo Studies
03-Exercise Mediainfo Studies
1
What we will cover
● Structs
○ Common Structs, Tuple Structs, Unit-Like Structs
2
Structs
3
Outline
● Basics on Structs
○ Differences with tuple
● Printing a Struct
● Working with and on structs
● Constructor
● Methods and Associated Functions
● Ownership, Borrowing and Self
4
Rev: Type tuple
{
let my_tuple = (135790, "Bob", false);
println!("{:?}", my_tuple); // Prints: (135790, “Bob”, false)
println!("{}", my_tuple.2); // Prints: false
}
5
Basics: Composed Type struct (1/3)
● Three types:
○ Common struct
○ Tuple struct
○ Unit struct
6
Basics: Composed Type struct (2/3)
https://doc.rust-lang.org/1.0.0/style/style/naming/README.html
7
Basics: Composed Type struct (3/3)
struct Student {
id: u32,
name: String,
graduated: bool
}
fn main() {
let my_struct = Student {
id: 135790,
name: String::from("Bob"),
graduated: false,
};
println!("{}", my_struct.name); // Prints: Bob
} 8
Printing a struct
● We can access single fields, but how about printing the whole struct?
● Similar to tuple, let’s try to use the built-in debug formatter with :?
{
let my_struct = Student {
id: 135790,
name: String::from("Bob"),
graduated: false
};
println!("{:?}", my_struct);
}
9
Printing a struct
error[E0277]: `Student` doesn't implement `Debug`
--> src/main.rs:13:22
|
13 | println!("{:?}", my_struct);
| ^^^^^^^^^ `Student` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Student`
= note: add `#[derive(Debug)]` to `Student` or manually `impl Debug for Student`
= note: this error originates in the macro `$crate::format_args_nl` which comes from the
expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more
info)
help: consider annotating `Student` with `#[derive(Debug)]`
|
1 | #[derive(Debug)]
|
10
What does this error tell us?
11
Traits Display and Debug (1/2)
● Macro println! calls the display formatter by default when reaching {}
● Trait Display:
○ Implemented for default types of the language
○ Makes the output looking nice and as expected
○ Not defined for types we created ourselves
12
Traits Display and Debug (2/2)
#[derive(Debug)]
struct Student {
id: u32, Output:
name: String, Student { id: 135790, name: "Bob", graduated: false }
graduated: bool
}
13
Structs and Mutability
{
let mut my_struct = Student {
id: 135790,
name: String::from("Bob"),
graduated: false
};
println!("Student name before: {}" , my_struct .name);
{
let mut my_struct1 = Student {
id: 135790,
name: String::from("Bob"),
graduated: false
};
let mut my_struct2 = Student {
id: 246800,
name: String::from("Bob"),
Lines are duplicates - Can we avoid this?
graduated: false
};
} 15
Struct update syntax
● Any solution…?
○ We will come back to this problem later
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1f7821eecd8d2a922f5aba2a2d7841c2
17
Constructor: Creating new structs (1/3)
18
Constructor: Creating new structs (2/3)
19
Constructor: Creating new structs (3/3)
● To summarize:
○ Functions producing new objects are called constructors
○ Such a function can be used to create new instances of a struct
○ No explicit assignment required if parameter names match field names
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=958127ea6eb56cc551004c40e76a398c
20
Function… or rather Method?
21
How to define a method
in the Rust language?
22
The Implementation Block
impl Student {
23
Extend our example for methods
#[derive(Debug)]
struct Course {
name: String,
passed: bool,
}
#[derive(Debug)]
struct Student {
id: u32,
name: String,
courses: [Course; 3]
}
24
Writing our first method (1/4)
impl Student {
fn check_graduation(&self) -> bool {
for course in self.courses.iter() {
if !course.passed {
return false; Iterate over our array of courses
}
}
true
}
}
25
Writing our first method (2/4)
impl Student {
fn check_graduation(&self) -> bool {
...
}
}
26
Writing our first method (3/4)
27
Writing our first method (4/4)
● Now, let’s create some courses and add them to our student
● At end the, we’ll see if Alice passed or not
fn main() {
let c1 = Course { name: String::from("INF-B-230"), passed: true };
let c2 = Course { name: String::from("INF-B-240"), passed: true };
let c3 = Course { name: String::from("INF-AQUA"), passed: true };
let my_struct = Student { name: String::from("Alice"), id: 246800, courses: [c1, c2, c3] };
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=516cbbcc0dd34ab1a38d6bccca39d2cd
28
Using self with ownership
transfer or without it?
29
self and Ownership
impl Student {
fn check_graduation(self) -> bool { Without &
for course in self.courses.iter() {
if !course.passed {
return false;
}
}
true
}
} 30
self and Ownership
fn main() {
...
31
self and Ownership
error[E0382]: borrow of moved value: `my_struct`
--> src/main.rs:50:22
|
40 | let my_struct = Student {
| --------- move occurs because `markus` has type `Student`, which does not implement the `Copy` trait
...
48 | println!("Checking if Alice has passed: {}", my_struct.check_graduation());
| ------------------ `my_struct` moved due to this method
call
50 | println!("{:?}", my_struct);
| ^^^^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `my_struct`
--> src/main.rs:17:25
|
17 | fn check_graduation(self) -> bool {
| ^^^^
32
What is self exactly?
33
Explaining self (1/4)
https://doc.rust-lang.org/std/fmt/#sign0
34
Explaining self (2/4)
fn main() {
let c1 = Course {
name: String::from("INF-B-230"), Output:
passed: true,
In main: Course {
}; name: "INF-B-230",
passed: true,
}
println!("In main: {:#?}", c1);
}
35
Explaining self (3/4)
● Now, we adjust main again and call the method defined on Course
fn main() {
let c1 = Course {
name: String::from("INF-B-230"),
passed: true,
};
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c9a39c6089400f7cff0376249e3b7fd2
36
Explaining self (4/4)
38
Methods: Updating structs (1/3)
39
Methods: Updating structs (2/3)
impl Course {
fn set_passed(&mut self, passed: bool) {
self.passed = passed;
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6e9127f04d62f442993f77a049e981d5
40
Methods: Updating structs (3/3)
fn main() {
let mut c1 = Course {
Output:
name: String::from("INF-B-230"),
Course after set_passed: Course {
passed: true, name: "INF-B-230",
}; passed: false,
}
c1.set_passed(false);
c1.print();
println!("Course after set_passed: {:#?}", c1);
}
41
Why using methods?
42
We mentioned another
type earlier. So, what is
an Associated Function?
43
Associated Functions
https://doc.rust-lang.org/std/string/struct.String.html
44
Method vs Associated Function
45
Constructor as Associated Function (1/2)
impl Student {
fn new(id: u32, name: String, courses: [Course; 3]) -> Self {
Self { id, name, courses }
}
} Self is equivalent to Student
46
Constructor as Associated Function (2/2)
fn main() {
let c1 = Course { name: String::from("INF-B-230"), passed: true };
let c2 = Course { name: String::from("INF-B-240"), passed: true };
let c3 = Course { name: String::from("INF-AQUA"), passed: true };
let my_struct = Student::new(246800, String::from("Alice"), [c1, c2, c3]);
println!("{:#?}", my_struct);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=38ae76cbfa9f648384f9f3e9957978de
47
Problem with inheriting data (1/3)
● With all the knowledge we have now, let’s come back to this problem
○ The compiler will give us the following error:
48
Problem with inheriting data (2/3)
49
Trait Clone
50
Problem with inheriting data (3/3)
#[derive(Debug, Clone)]
struct Course {
name: String,
passed: bool,
}
#[derive(Debug, Clone)]
struct Student {
id: u32,
name: String,
courses: [Course; 3],
}
51
Problem with inheriting data (3/3)
println!("{:#?}", my_struct1);
println!("{:#?}", my_struct2);
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9e29da2895459f0df8ef9e7c4ee7826c
52
We listed two other
types of structs, let’s
have a look at them.
53
Tuple Structs
54
Tuple Structs
55
Tuple Structs
#[derive(Debug)]
struct TupleStruct(u8, u8, u8);
fn main() {
let mut tuple = TupleStruct(0, 0, 0);
tuple.0 = 255; // Updating first index with “dot”
#[derive(Debug)]
struct RGB(u8, u8, u8);
#[derive(Debug)]
struct IPv4(u8, u8, u8, u8);
fn main() {
let red = RGB(255, 0, 0);
let local_ip = IPv4(127, 0, 0, 1);
}
57
Tuple Structs: Summary
58
Unit-Like Structs
59
Type Unit
https://doc.rust-lang.org/std/primitive.unit.html
60
Unit-Like Structs
fn main() {
let my_unit = UnitLikeStruct;
let same_unit_as_my_unit = UnitLikeStruct {};
println!(
"my_unit: {:?}, same_unit_as_my_unit: {:?}",
my_unit, same_unit_as_my_unit
);
}
61
Problems with Structs
62
Problems with Structs
63
Problems with Structs
● Simple example:
○ Two structs, each of which has a field
of the other
○ That means we would need infinite memory
■ Can we solve this now?
64
Problems with Structs
error[E0072]: recursive types `Course` and `Lecturer` have infinite size
--> main.rs:2:1
|
2 | struct Course {
| ^^^^^^^^^^^^^
...
5 | lecturer: Lecturer}
| -------- recursive without indirection
7 | #[derive(Debug, Clone)]
8 | struct Lecturer {
| ^^^^^^^^^^^^^^^
9 | name: String,
10 | course: Course
| ------ recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
5 ~ lecturer: Box<Lecturer>
6 | }
...
9 | name: String,
10 ~ course: Box<Course>
|
66
Overall Summary
● Using impl, we can define methods and associated functions for a struct
67
Feedback
68