1 tháng học Rust - Enums và Pattern Matching

1 tháng học Rust - Enums và Pattern Matching

Tin ngắn hàng ngày dành cho bạn
  • Mấy hôm trước OpenAI giới thiệu Deep Research - một công cụ duyệt web để nghiên cứu và cho ra một bản tổng hợp chỉ trong vài chục phút - so với nhiều giờ làm việc đối với con người, theo như họ công bố.

    Tính năng này hiện chỉ có sẵn cho người dùng Pro. Mặc dù chưa được dùng thử, nhưng qua nhiều bài viết đều nhấn mạnh vào sự ấn tượng trước khả năng của công cụ mới này. Nếu vẫn chưa biết Deep Research làm được gì thì bạn cứ hình dung như thế này: Nói với nó "Tôi cần thông tin nghiên cứu về lượng tiêu thụ cà phê của thế giới trong năm ngoái". Thế thôi! Ngồi chờ một lúc để nó tìm kiếm và tổng hợp lại kết quả và gửi lại cho bạn một bài báo cáo chi tiết. Chà, ghê thật chứ!

    Ngay lập tức huggingface đã lên một bài viết cố gắng tái tạo lại công cụ này theo cách của họ. Chi tiết tại Open-source DeepResearch – Freeing our search agents. Và không có gì ngạc nhiên khi cả 2 đều mang hơi hướng của AI Agents.

    » Xem thêm
  • Sống đủ lâu trong thế giới Internet, bạn có thể thấy rằng mọi người ở đây khá háo hức chạy theo xu hướng và chúng lan truyền với tốc độ chóng mặt.

    Chỉ vài tháng trước, chúng ta vẫn còn kinh ngạc về trí thông minh của các mô hình ngôn ngữ lớn (LLM) có thể trả lời giống như con người, và ngay sau đó, chúng đã được cập nhật với khả năng suy nghĩ và lý luận đáng kinh ngạc. Chúng được ứng dụng rộng rãi không chỉ trong lĩnh vực lập trình. Gần đây, thuật ngữ AI Agents đã tạo nên một sự khuấy động.

    Vậy, AI Agents là gì? Trong bài viết ngắn này, tất nhiên là không thể đưa ra một định nghĩa ngắn gọn nhưng toàn diện. Bạn đọc có thể tham khảo bài viết rất chi tiết này tại đây Agents | Chip Huyền. Để dễ hình dung hơn, AI Agents có thể được coi là một người hoặc một thực thể nào đó. Bản thân các Agents được trang bị tất cả các công cụ cần thiết. Từ đó, các Agents có thể kết hợp chúng để hoàn thành một nhiệm vụ mà chúng ta giao.

    Vẫn còn hơi mơ hồ phải không? Một ví dụ thực tế là khi bạn ra lệnh cho các Agents truy cập Facebook vào lúc 8 giờ tối mỗi ngày, kiểm tra bất kỳ tin tức nổi bật nào từ bạn bè, sau đó gửi tóm tắt đến Telegram. Vậy là xong!

    » Xem thêm
  • Hôm qua đến nay, lượt truy cập tới từ Facebook tăng đột biến. Thường như thế là do ai đó chia sẻ bài viết của blog vào một nhóm nào đó.

    Cơ mà lần này là liên kết trực tiếp đến trang chủ luôn. Tò mò ghê, không biết ai chia sẻ, chia sẻ ở đâu nữa. Muốn biết để tìm hiểu "insight" ghê 🥹

    » Xem thêm

Vấn đề

Về enums - một cấu trúc dữ liệu liệt kê mà có thể ai cũng biết. Enums cho phép xác định một loại bằng cách liệt kê các biến thể có thể có của nó. Trong mỗi ngôn ngữ lập trình, enums có cách khai báo và sử dụng khác nhau. Đối với Rust, enums được sử dụng khá thường xuyên vì nhiều lợi ích mà nó mang lại.

Bài viết ngày hôm nay chúng ta sẽ cùng nhau tìm hiểu về enums, xem nó có gì hay ho hơn so với các ngôn ngữ khác không nhé!

Enums

Một enums được khai báo như sau:

enum IpAddrKind {
    V4,  
    V6,  
}

Sau đó có thể sử dụng:

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

Enums trong Rust cũng lưu trữ được dữ liệu.

enum IpAddr {
    V4(String),  
    V6(String),  
}

let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));

Thậm chí, chúng ta còn có thể khai báo thêm phương thức cho nó.

enum IpAddr {
    V4(String),  
    V6(String),  
}

impl IpAddr {
    fn call(&self) {
        println!("Hello from IpAddr!");
    }
}

let home = IpAddr::V4(String::from("127.0.0.1"));
home.call();

Option là một enums được định nghĩa sẵn ở trong Rust, nó có một sứ mệnh quan trọng trong việc xử lý dữ liệu null.

Một Option có dạng Generic như sau.

enum Option<T> {
    None,  
    Some(T),  
}

Nhiều ngôn ngữ lập trình khác, chúng ta quá quen thuộc với kiểu dữ liệu null đại diện cho việc không có giá trị nào. Rust không có kiểu dữ liệu null, hầu hết trường hợp cần sử dụng null thì sẽ chuyển qua sử dụng enums Option.

None đại diện cho “không có gì” còn Some đại diện cho sự hiện hữu của một dạng dữ liệu nào đó. Lấy ví dụ.

let none: Option<i8> = None;
let five: Option<i8> = Some(5);
let six: Option<i8> = Sone(6);

Và dĩ nhiên chúng ta không thể thực hiện các phép tính trực tiếp trên kiểu dữ liệu Option này một cách bình thường.

// error
let sum = none + five;

// error
let sum = five + six;

Vậy thì làm cách nào để sử dụng được enums nói chung cũng như Option nói riêng?

Matching

Hầu hết việc xác định enums nhằm mục đích phân loại và xử lý dữ liệu theo các dạng được định nghĩa từ trước, chính vì thế Rust có cấu trúc xử lý loại rất mạnh mẽ là match hay còn gọi là “khớp mẫu”.

enum Coin {
    Penny,  
    Nickel,  
    Dime,  
    Quarter,  
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,  
        Coin::Nickel => 5,  
        Coin::Dime => 10,  
        Coin::Quarter => 25,  
    }
}

Hàm value_in_cents nhận vào một enums có kiểu Coin từ đó trả về giá trị tương ứng với tên của các đồng xu bằng cách sử dụng cú pháp match.

Đối với Option, chúng ta cũng sử dụng match để xử lý các trường hợp NoneSome, cũng như thực hiện các phép tính cơ bản mà Some nắm giữ như ví dụ ở đầu bài viết.

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,  
        Some(i) => Some(i + 1),  
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);

Hàm plus_one nhận vào một Option<i32> và cộng thêm 1 vào giá trị của nó. Bằng cách khớp mẫu, hàm trả về None nếu như x là None, ngược lại nếu x là loại Some, tức là nó có giá trị thì sẽ trả về giá trị Some mới bằng cách cộng thêm 1.

Cho dễ hình dung, match gần giống với lệnh swich…case trong JavaScript. Trong khi switch đưa ra một giá trị khi nào khớp với giá trị trong case thì hàm xử lý đó ngay lập tức được thực thi. Nếu như switch…case có trường hợp default, nghĩa là khi các giá trị trong tất cả case không khớp thì cuối cùng hàm xử lý default được thực hiện. Trong Rust cũng có, người ta gọi là “Placeholder” hay “trình giữ chỗ”.

let dice_roll = 9;
match dice_roll {
    3 => add_fancy_hat(),  
    7 => remove_fancy_hat(),  
    other => move_player(other),  
}

fn add_fancy_hat() {}
fn remove_fancy_hat() {}
fn move_player(num_spaces: u8) {}

Quay trở lại với trường hợp sử dụng Option, đôi khi chúng ta không quan tâm đến None lắm mà chỉ đơn giản là muốn thao tác với dữ liệu nếu có của Some. Ví dụ dưới đây luôn phải khai báo thêm một trình giữ chỗ để “không phải làm gì”.

let config_max = Some(3u8);
match config_max {
    Some(max) => println!("The maximum is configured to be {}", max),  
    _ => (),  
}

Điều này lặp lại một cách nhàm chán và thừa thãi, thay vào đó, Rust gợi ý chúng ta sử dụng kết hợp iflet để chỉ xử lý riêng cho một trường hợp cụ thể của một enums.

let config_max = Some(3u8);
if let Some(max) = config_max {
    println!("The maximum is configured to be {}", max);
}

Cuối cùng, vẫn có một lưu ý quan trọng về quyền sở hữu khi khớp mẫu khi Some giữ các giá trị tham chiếu. Bạn đọc có thể tham khảo thêm tại The Rust Programming Language - How Matches Interact with Ownership.

Cao cấp
Hello

5 bài học sâu sắc

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Mỗi sản phẩm đi kèm với những câu chuyện. Thành công của người khác là nguồn cảm hứng cho nhiều người theo sau. 5 bài học rút ra được đã thay đổi con người tôi mãi mãi. Còn bạn? Hãy bấm vào ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.

Bình luận (1)

Nội dung bình luận...
Avatar
Ẩn danh1 năm trước
Mình cũng bắt đầu tìm hiểu về rust, bạn có muốn lập nhóm ngồi cf trao đổi để học không?
Trả lời
Avatar
Xuân Hoài Tống1 năm trước
Chào bạn, rất vui khi nhận được lời đề nghị của bạn. Mình viết ra series tự học Rust để tạo cam kết cũng như ghi chép lại những gì học được, qua đó tóm tắt lại một cách cô đọng cho người đọc tham khảo. Tuy nhiên thì mình có nhiều lý do để rất khó lập được nhóm và cùng nhau trao đổi, như công việc và gia đình. Nhưng không sao, mình vẫn có thời gian cuối ngày để viết blog cũng như rất sẵn sàng trao đổi với bạn (dù không được realtime cho lắm). Hoặc nếu bạn cũng viết blog thì có thể để lại địa chỉ để cùng nhau học hỏi thêm :D
Bấm hoặc cuộn mạnh để sang bài mới