rust-by-practice/en/src/compound-types/struct.md

231 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Struct
### There types of structs
1. 🌟 We must specify concrete values for each of the fields in struct.
```rust,editable
// fix the error
struct Person {
name: String,
age: u8,
hobby: String
}
fn main() {
let age = 30;
let p = Person {
name: String::from("sunface"),
age,
};
println!("Success!")
}
```
2. 🌟 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.
```rust,editable
struct Unit;
trait SomeTrait {
// ...Some behavours defines here
}
// We don't care the the fields are in Unit, but we care its behaviors.
// So we use a struct with no fields and implement some behaviors for it
impl SomeTrait for Unit { }
fn main() {
let u = Unit;
do_something_with_unit(u);
println!("Success!")
}
// fill the blank to make the code work
fn do_something_with_unit(u: __) { }
```
3. 🌟🌟🌟 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 give the whole tuple a name, but don't care the fields's names.
```rust,editable
// fix the error and fill the blanks
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let v = Point(__, __, __);
check_color(v);
println!("Success!")
}
fn check_color(p: Color) {
let (x, _, _) = p;
assert_eq!(x, 0);
assert_eq!(p.1, 127);
assert_eq!(__, 255);
}
```
### Operate on structs
4. 🌟 You can make a whole struct mutable when instantiate it, but Rust doesn't allow us to mark only certain fields as mutable.
```rust,editable
// fill the blank and fix the error without adding/removing new line
struct Person {
name: String,
age: u8,
}
fn main() {
let age = 18;
let p = Person {
name: String::from("sunface"),
age,
};
// how can you believe sunface is only 18?
p.age = 30;
// fill the lank
__ = String::from("sunfei");
println!("Success!")
}
```
5. 🌟 Using *field init shorthand syntax* to reduct repetitions.
```rust,editable
// fill the blank
struct Person {
name: String,
age: u8,
}
fn main() {
println!("Success!")
}
fn build_person(name: String, age: u8) -> Person {
Person {
age,
__
}
}
```
6. 🌟 You can create instance from other instance with *struct update syntax*
```rust,editable
// fill the blank to make the code work
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let u1 = User {
email: String::from("someone@example.com"),
username: String::from("sunface"),
active: true,
sign_in_count: 1,
};
let u2 = set_email(u1);
println!("Success!")
}
fn set_email(u: User) -> User {
User {
email: String::from("contact@im.dev"),
__
}
}
```
### Print the structs
7. 🌟🌟 We can use `#[derive(Debug)]` to [make a struct prinable](https://doc.rust-lang.org/book/ch05-02-example-structs.html?highlight=%23%5Bderive(Debug)%5D#adding-useful-functionality-with-derived-traits).
```rust,editable
// fill the blanks to make the code work
#[__]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let scale = 2;
let rect1 = Rectangle {
width: dbg!(30 * scale), // print debug info to stderr and assign the value of `30 * scale` to `width`
height: 50,
};
dbg!(&rect1); // print debug info to stderr
println!(__, rect1); // print debug info to stdout
}
```
### 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
```rust,editable
fn main() {
#[derive(Debug)]
struct Person {
name: String,
age: Box<u8>,
}
let person = Person {
name: String::from("Alice"),
age: Box::new(20),
};
// `name` is moved out of person, but `age` is referenced
let Person { name, ref age } = person;
println!("The person's age is {}", age);
println!("The person's name is {}", name);
// Error! borrow of partially moved value: `person` partial move occurs
//println!("The person struct is {:?}", person);
// `person` cannot be used but `person.age` can be used as it is not moved
println!("The person's age from person struct is {}", person.age);
}
```
#### Exercises
8. 🌟🌟
```rust,editable
// fix errors to make it work
#[derive(Debug)]
struct File {
name: String,
data: String,
}
fn main() {
let f = File {
name: String::from("readme.md"),
data: "Rust By Practice".to_string()
};
let _name = f.name;
// ONLY modify this line
println!("{}, {}, {:?}",f.name, f.data, f);
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it