The Rust Programming Language
- Before Start
- Struct: custom data type that lets you package together and name multiple related values
that make up a meaningful group
- Structs and enums are the building blocks for creating new types in your program's domain
to take full advantage of Rust's compile-time type checking
- Defining and Instantiation Structs
- Like tuples, the pieces of a struct can be different types
- Unlike tuples, we have to name each piece of data so it's more clear
- inside curly brackets, we defind the names and types of the pieces of data called fields
- not rely on the same order of data, just like a general template
- if we mutate the instance, the entire instance must be mutable, not just only certain fields
- Using the Field Init Shorthand
- if function parameter name equals to struct field name, we can make it shorthand (only write once)
- Creating Instances from Other Instances with Struct Update Syntax
- The syntax .. specifies that the remaining fields not explicitly set should have the same value
as the fields in the given instance
- Using Tuple Structs Without Named Fields to Create Different Types
- tuple structs
- useful when we want to give the whole tuple a name
and make the tuple a different type from other tuples,
and when naming each field as in a regular struct would be verbose or redundant
- Unit-Like Structs Without Any Fields
- Unit-Like Structs: structs that don't have any fields
- useful when we need to implement a trait on some type but don't have any data
that we want to store in the type itself
- Ownership of Struct Data
- Lifetimes ensure that the data referenced by a struct is valid for as long as the struct is
fn main() {
let mut user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("someone@example.com"),
sign_in_count: 1,
};
let user2 = User {
email: String::from("another@example.com"),
..user1
};
println!("{}", user1.username); // compile error
}
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
- An Example Program Using Structs
- Refactoring with Tuples
- Refactoring with Structs: Adding More Meaning
- Adding Useful Functionality with Derived Traits
fn main() {
// let width1 = 30;
// let height1 = 50;
// let rect1 = (30, 50);
let rect1 = Rectangle {
width: dbg!(30 * 2),
height: 50,
};
println!(
"The area of the rectangle is {} square pixels.",
// area(width1, height1)
// area(rect1)
area(&rect1)
);
println!("rect1 is {:#?}", rect1);
dbg!(&rect1); // if no reference, compile time error at the bottom code
println!("rect1 is {:#?}", rect1);
}
// fn area(width: u32, height: u32) -> u32 {
// width * height
// }
// fn area(dimensions: (u32, u32)) -> u32 {
// dimensions.0 * dimensions.1
// }
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn area(rectangle: &Rectangle) -> u32 {
rectangle.width * rectangle.height
}
- Method Syntax
- Unlike functions, methods are defined within the context of a struct (or an enum or a trait object)
and their first parameter is always self
which represents the instance of the struct the method is being called on
- Defining Methods
- &self is actually for self: &Self
- Having a method that takes ownership of the instance by using just Self as the first parameter is rare
-> usually used when the method transforms self into something else
and we want to prevent the caller from using the original instance after the transformations
- Rust does not implement automatically for struct fields for getters.
(method and field name are same)
- Where's the -> Operator?
- Methods with More Parameters
- Associated Functions
- not methods
- often used for constructors that will return a new instance of the struct
- Multiple impl Blocks
- Summary
fn main() {
// let rect1 = Rectangle {
// width: 30,
// height: 50,
// };
// println!(
// "The area of the rectangle is {} square pixels.",
// rect1.area()
// );
let rect1 = Rectangle {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 10,
height: 40,
};
let rect3 = Rectangle {
width: 60,
height: 45,
};
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
let sq = Rectangle::square(3);
dbg!(sq);
}
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
'Personal-Study > Rust' 카테고리의 다른 글
[Rust 문서 읽기] 7. Managing Growing Projects with Packages, Crates, and Modules (모듈) (0) | 2023.02.11 |
---|---|
[Rust 문서 읽기] 6. Enums and Pattern Matching (열거형과 패턴 매칭) (0) | 2023.02.05 |
[Rust 문서 읽기] 4. Understanding Ownership (소유권 이해하기) (0) | 2023.01.29 |
[Rust 문서 읽기] 3. Common Programming Concepts (보편적인 프로그래밍 개념) (0) | 2023.01.29 |
[Rust 문서 읽기] 2. Programming a Guessing Game (추리 게임 튜토리얼) (0) | 2023.01.29 |
댓글