Skip to content

Commit 71bbb3d

Browse files
authored
Merge pull request #79 from rust-tieng-viet/claude/expand-rust-idioms-011CUVLLByM8zs4E9ZLfXBr9
feat: Rust Idioms
2 parents 074fd73 + c18a8b8 commit 71bbb3d

File tree

9 files changed

+2654
-4
lines changed

9 files changed

+2654
-4
lines changed

src/SUMMARY.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@
186186
- [Concatenating strings with `format!`](./idioms/format.md)
187187
- [Constructor](./idioms/constructor.md)
188188
- [The Default Trait](./idioms/default-trait.md)
189-
- [Finalisation in destructors]()
189+
- [Finalisation in destructors](./idioms/finalisation-destructors.md)
190190
- [Temporary mutability](./idioms/temporary-mutability.md)
191-
- [Aim For Immutability in Rust](./idioms/aim-for-immutability.md)
191+
- [Aim For Immutability in Rust](./idioms/aim-for-immutability.md)
192+
- [`mem::replace` and `mem::take`](./idioms/mem-replace.md)
193+
- [Privacy for extensibility](./idioms/privacy-for-extensibility.md)
194+
- [Iterating over `Option`](./idioms/option-iter.md)
195+
- [Pass variables to closure](./idioms/pass-variables-to-closure.md)
196+
- [`let-else` pattern](./idioms/let-else.md)

src/idioms/constructor.md

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Constructor
22

3-
Rust không có constructors, thay vào đó có một convention là sử dụng `new` method ([Associated Functions](https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions)) để tạo một instance mới của struct hoặc enum.
3+
Rust không có constructors như các ngôn ngữ hướng đối tượng khác (Java, C++, etc.). Thay vào đó, Rust sử dụng convention là tạo [Associated Functions](https://doc.rust-lang.org/stable/book/ch05-03-method-syntax.html#associated-functions) có tên `new` để khởi tạo instance mới.
4+
5+
## Convention cơ bản: `new()`
46

57
```rust
68
struct Point {
@@ -20,4 +22,206 @@ fn main() {
2022
}
2123
```
2224

25+
## Tại sao không dùng `pub` cho fields?
26+
27+
Trong thực tế, chúng ta thường giữ các fields là private và cung cấp constructor `new()` để kiểm soát việc khởi tạo:
28+
29+
```rust
30+
pub struct Rectangle {
31+
width: u32,
32+
height: u32,
33+
}
34+
35+
impl Rectangle {
36+
// Constructor đảm bảo width và height hợp lệ
37+
pub fn new(width: u32, height: u32) -> Result<Self, String> {
38+
if width == 0 || height == 0 {
39+
return Err("Width and height must be positive".to_string());
40+
}
41+
Ok(Rectangle { width, height })
42+
}
43+
44+
pub fn area(&self) -> u32 {
45+
self.width * self.height
46+
}
47+
}
48+
49+
fn main() {
50+
let rect = Rectangle::new(10, 20).unwrap();
51+
println!("Area: {}", rect.area());
52+
53+
// Lỗi compile: fields are private
54+
// println!("{}", rect.width);
55+
}
56+
```
57+
58+
## Multiple Constructors
59+
60+
Rust cho phép tạo nhiều constructor methods với tên khác nhau:
61+
62+
```rust
63+
pub struct Color {
64+
r: u8,
65+
g: u8,
66+
b: u8,
67+
}
68+
69+
impl Color {
70+
pub fn new(r: u8, g: u8, b: u8) -> Self {
71+
Color { r, g, b }
72+
}
73+
74+
pub fn from_hex(hex: u32) -> Self {
75+
Color {
76+
r: ((hex >> 16) & 0xFF) as u8,
77+
g: ((hex >> 8) & 0xFF) as u8,
78+
b: (hex & 0xFF) as u8,
79+
}
80+
}
81+
82+
pub fn black() -> Self {
83+
Color { r: 0, g: 0, b: 0 }
84+
}
85+
86+
pub fn white() -> Self {
87+
Color { r: 255, g: 255, b: 255 }
88+
}
89+
}
90+
91+
fn main() {
92+
let c1 = Color::new(255, 0, 0); // Red
93+
let c2 = Color::from_hex(0x00FF00); // Green
94+
let c3 = Color::black(); // Black
95+
let c4 = Color::white(); // White
96+
}
97+
```
98+
99+
## Builder Pattern cho complex constructors
100+
101+
Khi struct có nhiều parameters, nên sử dụng Builder Pattern:
102+
103+
```rust
104+
pub struct User {
105+
username: String,
106+
email: String,
107+
age: Option<u32>,
108+
country: Option<String>,
109+
}
110+
111+
pub struct UserBuilder {
112+
username: String,
113+
email: String,
114+
age: Option<u32>,
115+
country: Option<String>,
116+
}
117+
118+
impl User {
119+
pub fn builder(username: String, email: String) -> UserBuilder {
120+
UserBuilder {
121+
username,
122+
email,
123+
age: None,
124+
country: None,
125+
}
126+
}
127+
}
128+
129+
impl UserBuilder {
130+
pub fn age(mut self, age: u32) -> Self {
131+
self.age = Some(age);
132+
self
133+
}
134+
135+
pub fn country(mut self, country: String) -> Self {
136+
self.country = Some(country);
137+
self
138+
}
139+
140+
pub fn build(self) -> User {
141+
User {
142+
username: self.username,
143+
email: self.email,
144+
age: self.age,
145+
country: self.country,
146+
}
147+
}
148+
}
149+
150+
fn main() {
151+
let user = User::builder(
152+
"duyet".to_string(),
153+
"[email protected]".to_string()
154+
)
155+
.age(25)
156+
.country("Vietnam".to_string())
157+
.build();
158+
}
159+
```
160+
161+
## Constructor với validation
162+
163+
```rust
164+
pub struct Email {
165+
address: String,
166+
}
167+
168+
impl Email {
169+
pub fn new(address: String) -> Result<Self, &'static str> {
170+
if !address.contains('@') {
171+
return Err("Invalid email address");
172+
}
173+
Ok(Email { address })
174+
}
175+
176+
pub fn as_str(&self) -> &str {
177+
&self.address
178+
}
179+
}
180+
181+
fn main() {
182+
match Email::new("[email protected]".to_string()) {
183+
Ok(email) => println!("Valid email: {}", email.as_str()),
184+
Err(e) => println!("Error: {}", e),
185+
}
186+
}
187+
```
188+
189+
## Khi nào dùng `new()` vs `default()`?
190+
191+
- **`new()`**: Khi cần parameters để khởi tạo
192+
- **`default()`**: Khi có thể tạo instance với giá trị mặc định hợp lý
193+
194+
Thông thường, struct sẽ implement cả hai:
195+
196+
```rust
197+
#[derive(Debug)]
198+
pub struct Config {
199+
pub host: String,
200+
pub port: u16,
201+
}
202+
203+
impl Config {
204+
pub fn new(host: String, port: u16) -> Self {
205+
Config { host, port }
206+
}
207+
}
208+
209+
impl Default for Config {
210+
fn default() -> Self {
211+
Config {
212+
host: "localhost".to_string(),
213+
port: 8080,
214+
}
215+
}
216+
}
217+
218+
fn main() {
219+
let config1 = Config::new("example.com".to_string(), 3000);
220+
let config2 = Config::default();
221+
222+
println!("{:?}", config1);
223+
println!("{:?}", config2);
224+
}
225+
```
226+
23227
{{#include ./default-trait.md }}

0 commit comments

Comments
 (0)