0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Hiểu Rõ Về Biến và Tính Thay Đổi Trong Rust

Đăng vào 1 tuần trước

• 5 phút đọc

Mở đầu

Chào mừng các bạn đã quay trở lại với chuỗi bài viết về Rust! Ở bài viết trước, chúng ta đã hoàn thành việc thiết lập môi trường cho Rust. Hôm nay, chúng ta sẽ cùng khám phá những điều thú vị về biến (Variables) và hằng số (Constants) trong Rust, cùng xem chúng khác biệt như thế nào so với các ngôn ngữ lập trình khác.

Biến (Variables)

Biến trong Rust tương tự như các ngôn ngữ lập trình khác, giúp chúng ta lưu trữ các giá trị từ số, chữ cái cho đến các kiểu dữ liệu phức tạp hơn. Tuy nhiên, Rust có một số quy tắc đặc biệt khi sử dụng biến.

Mặc định là Immutable

Khi khởi tạo biến trong Rust, chúng ta sử dụng từ khóa let. Mặc định, biến được khai báo sẽ là immutable (không thể thay đổi). Điều này có nghĩa là sau khi khai báo, bạn không thể thay đổi giá trị của biến đó.

rust Copy
fn main() {
    let name = "Quan";
    println!("My name is: {name}");
    name = "Quan Troy";
    println!("My name is: {name}");
}
shell Copy
// Ouput: Error message "cannot assign twice to immutable variable `name`"
// Bởi vì bạn đã cố gán giá trị cho `name` trong khi nó là Immutable

Trình biên dịch Rust sẽ đảm bảo rằng nếu bạn khai báo một giá trị là immutable, nó sẽ thực sự không thay đổi trong suốt thời gian thực thi, giúp bạn quản lý mã nguồn tốt hơn và tránh những lỗi không mong muốn do việc thay đổi giá trị biến mà bạn không hay biết.

Tuy nhiên, bạn có thể khai báo một biến là mutable (có thể thay đổi) bằng cách thêm mut vào trước tên biến. Việc này không chỉ cho phép biến thay đổi, mà cũng giúp người đọc code nhận biết rằng biến này có thể thay đổi giá trị sau này. Hãy cùng sửa lại ví dụ trên một chút:

rust Copy
fn main() {
    let mut name = "Quan";
    println!("My name is: {name}");
    name = "Quan Troy";
    println!("My name is: {name}");
}
shell Copy
//Output
% cargo run      
   Compiling hello-world v0.1.0 (/<PATH>/hello-world)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/hello-world`
My name is: Quan
My name is: Quan Troy

Ở đây, bạn đã thêm mut để biến name có thể thay đổi giá trị. Nhưng khi nào nên thêm mut và khi nào không? Việc này yêu cầu bạn phải hiểu rõ về mã nguồn của mình để có thể quyết định sử dụng biến immutable hay mutable hiệu quả. Điều này sẽ giúp tránh việc khai báo không cần thiết trong trường hợp bạn không muốn biến của mình thay đổi.

Sự Ẩn Danh (Shadowing)

Rust cho phép bạn "biến hình" để biến có cùng tên xuất hiện hai lần, mà không gây ra xung đột. Biến sau sẽ làm "lu mờ" biến trước, và trình biên dịch chỉ nhận diện biến thứ hai.

rust Copy
fn main() {
    let name = "Quan";
    let name = "Quan Troy";
    println!("My name is: {name}");
}
shell Copy
//Ouput: My name is Quan Troy

Để kiểm tra xem đây có phải là hai biến khác nhau hay không, bạn có thể thêm dòng code println!("Address of name: {:p}", &name); bên dưới để in ra địa chỉ ô nhớ của name được khai báo lần thứ nhất và thứ hai.

Mặc dù ví dụ trên có vẻ tương tự như việc sử dụng mut, nhưng thực tế chúng hoàn toàn khác nhau. Biến được khai báo qua Shadowing vẫn là immutable (không thay đổi) khi được gán lại. Một lợi ích khác của Shadowing là bạn có thể tạo ra biến mới cùng tên nhưng khác kiểu dữ liệu, điều mà mut không thực hiện được.

rust Copy
let name = "Quan Troy";
let name = name.len(); // Không có vấn đề gì
rust Copy
let name = "Quan Troy";
name = name.len(); // Lỗi không cho phép mutate thay đổi kiểu dữ liệu

Shadowing giúp bạn giữ cho mã nguồn gọn gàng hơn, tránh việc phải đặt tên biến dài dòng như name_strname_num mà chỉ cần name là đủ.

Kiểu Dữ Liệu

Rust rất thông minh và có thể tự động suy đoán loại dữ liệu của biến. Tuy nhiên, trong một số trường hợp, bạn sẽ cần chỉ rõ để Rust hiểu:

rust Copy
let secret_number: u32 = 42; // u32 là số nguyên không âm 32-bit

Phạm Vi (Scope)

Biến trong Rust có phạm vi sống trong những "ngôi nhà" được gọi là scope, được định nghĩa trong dấu ngoặc nhọn {}. Khi ra khỏi phạm vi này, biến sẽ bị xóa để giải phóng bộ nhớ:

rust Copy
{
    let ghost = "Quan!";
} // ghost biến mất ở đây!

Hằng Số (Constants)

Hằng số cũng là các giá trị không thay đổi giống như biến immutable, nhưng có một số khác biệt. Hằng số không thể sử dụng mut, chúng không chỉ mặc định mà luôn luôn là immutable. Khi khai báo, bạn sử dụng từ khóa constphải chỉ định kiểu dữ liệu. Quy tắc đặt tên trong Rust cho hằng số là sử dụng tất cả chữ hoa và dấu gạch dưới giữa các từ.

rust Copy
fn main() {
    const MAX_POINT: u32 = 100_000; 
    println!("Max point: {}", MAX_POINT);
}
shell Copy
//Output: Max point: 100000

Phạm Vi của Hằng Số

Hằng số có thể được khai báo ở phạm vi toàn cục hoặc cục bộ. Không thể khai báo cùng một hằng số hai lần trong cùng một phạm vi (scope), nhưng nếu ở các phạm vi khác nhau thì điều đó là hoàn toàn có thể.

rust Copy
const MAX_POINT: u32 = 100; //global scope
//const MAX_POINT: u32 = 1000; -> ERROR
fn main() {
    const MAX_POINT: u32 = 100_000; // OK -> chỉ có scope trong "{}" của hàm main
    println!("Max point: {}", MAX_POINT);
}
shell Copy
//Output: Max point: 100000

Tổng kết

Trong bài viết này, chúng ta đã xem xét những khái niệm cơ bản về biến trong Rust, bao gồm sự khác biệt giữa immutable và mutable, tính chất của hằng số (constants) và Shadowing. Việc quản lý biến trong Rust không chỉ đảm bảo an toàn mà còn nâng cao tính rõ ràng và hiệu quả của mã nguồn. Hy vọng bài viết này sẽ giúp bạn tự tin hơn khi làm việc với Rust. Nếu bạn có thắc mắc nào, đừng ngần ngại để lại câu hỏi dưới bài viết nhé! Chúc bạn trở thành một Rustacean thật giỏi!

Cảm ơn bạn đã dành thời gian đọc bài viết này.

Tài Liệu Tham Khảo

Hướng dẫn chính thức về Rust
source: viblo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào