Menu

Enum trong Zero: kiểu liệt kê đơn giản không có payload

Cách enum hoạt động trong Zero: khai báo một tập cố định các biến thể có tên, so sánh giá trị, và ranh giới giữa enum (nhãn thuần) với choice (tagged union).

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Khai báo một enum

enum khai báo một kiểu mà giá trị của nó thuộc một tập cố định các biến thể có tên:

enum Status {
    ready,
    failed,
}

Giờ Status là một kiểu có đúng hai giá trị: Status.ready và Status.failed. Không có gì khác có thể là một Status.

Ngữ pháp được cố tình giữ thật nhỏ:

  • enum Name { mở phần khai báo.
  • Mỗi dòng liệt kê một tên biến thể, ngăn cách bằng dấu phẩy.
  • } đóng lại.

Không payload, không giá trị phân biệt, không phương thức sinh tự động: chính điều đó giữ cho enum là "kiểu tổng nhỏ" trong Zero.

Dùng một enum

Bạn gọi tên một biến thể bằng cách thêm tên kiểu enum phía trước:

let state: Status = Status.ready

Chú thích : Status là không bắt buộc khi vế phải đã xác định kiểu; trong hầu hết trường hợp bạn có thể viết:

let state = Status.ready

và trình biên dịch sẽ suy ra kiểu là Status.

So sánh giá trị enum

Hai giá trị enum bằng nhau khi chúng là cùng một biến thể:

if state == Status.ready {
    check world.out.write("ready\n")
} else {
    check world.out.write("not ready\n")
}

Đó là cách đơn giản nhất để rẽ nhánh theo enum. Để phân tích đầy đủ, tức là xử lý tường minh mọi biến thể, hãy dùng match:

match state {
    .ready  => { check world.out.write("ready\n") }
    .failed => { check world.out.write("failed\n") }
}

Ưu thế của match so với if/else if lộ rõ khi bạn thêm biến thể thứ ba về sau. Trình biên dịch sẽ chỉ ra mọi match đang thiếu trường hợp mới; một chuỗi if/else thì âm thầm rơi xuống nhánh mặc định.

Choice và match trình bày match chi tiết hơn. Nó dùng được cho cả enum lẫn choice.

Một ví dụ hoàn chỉnh

Mẫu chính thức của Zero đặt enum và choice cạnh nhau trong cùng một tệp:

Status không làm gì trong đoạn code này: nó có mặt để cho thấy sự tương phản. Một biến thể choice gắn payload vào biến (value, message) khi được so khớp; một biến thể enum không gắn gì cả vì chẳng có gì để gắn.

Enum hay choice: cây quyết định nhanh

Một quy tắc ngắn:

  • Các biến thể chỉ là nhãn → enum.
  • Các biến thể phải mang dữ liệu → choice.

Nếu bạn đang mô hình hóa các trạng thái vòng đời và đến lúc cần gắn thông báo lỗi vào trạng thái "failed", hãy đổi kiểu từ enum sang choice. Mỗi biến thể có thêm một kiểu payload, và các nhánh match phía sau có thêm biến gắn cho payload đó. Đây là một lần refactor mà trình biên dịch dẫn bạn đi từng bước.

Cụ thể:

// Before - enum, no payloads
enum Status {
    ready,
    failed,
}

// After - choice with payloads on each variant
choice Status {
    ready: Void,
    failed: String,
}

Các biến thể có payload Void chỉ là nhãn ở dạng choice. Bạn có thể dùng enum hoặc choice cho cùng những trạng thái logic; hãy chọn enum khi bạn thật sự không cần gắn dữ liệu.

Trường hợp sử dụng

Vài ví dụ thường ngày mà enum là câu trả lời đúng:

  • Vòng đời không có metadata. Loading, Ready, Empty: trạng thái thuần, không payload.
  • Chế độ. Read, Write, Append cho chế độ mở tệp.
  • Hướng. North, South, East, West.
  • Mức độ log. Trace, Debug, Info, Warn, Error. (Sau này bạn có thể muốn thêm thông báo, lúc đó bạn sẽ chuyển sang choice.)
  • Ngày trong tuần. Một ví dụ kinh điển.

Bất cứ khi nào bạn định dùng một hằng số nguyên "ma thuật" (0 = đang chờ, 1 = đang hoạt động, 2 = đã xong), một enum gần như luôn rõ ràng hơn.

Ghi chú về phong cách

  • Tên biến thể viết thường khớp với phong cách đặt tên định danh của Zero trong toàn bộ ngôn ngữ.
  • Dấu phẩy cuối sau biến thể cuối cùng là được (và nên dùng để diff gọn hơn: thêm biến thể mới không làm thay đổi dòng trước đó).
  • Giữ danh sách enum ngắn. Nếu bạn có cả chục biến thể và nhiều trong số đó muốn có payload, có lẽ thứ bạn cần là một choice, hoặc một thiết kế lại, chứ không phải một enum lớn hơn.

Tiếp theo: choice và match

Bước tiếp theo tự nhiên là người anh em giàu tính năng hơn: choice và match, kiểu tagged union của Zero cùng cấu trúc so khớp mẫu đi kèm.

Câu hỏi thường gặp

Enum trong Zero là gì?

enum khai báo một kiểu mà giá trị của nó là một trong một tập cố định các biến thể có tên: những nhãn không mang payload nào. Ví dụ: enum Status { ready, failed }. Một giá trị kiểu Status chỉ có thể là đúng một trong Status.ready hoặc Status.failed, và trình biên dịch đảm bảo điều đó.

Enum khác choice thế nào?

Các biến thể của enum là nhãn thuần, chúng không mang dữ liệu. choice là một tagged union: mỗi biến thể có một kiểu payload đi kèm, như choice Result { ok: i32, err: String }. Dùng enum khi bạn chỉ cần phân biệt các trường hợp bằng tên; dùng choice khi mỗi trường hợp mang thêm thông tin.

Làm sao kiểm tra một giá trị đang là biến thể enum nào?

So sánh giá trị với biến thể: if status == Status.ready { ... }. Để rẽ nhánh đầy đủ qua mọi biến thể, hãy dùng match: trình biên dịch sẽ cảnh báo nếu bạn bỏ sót biến thể nào, và đó là lý do chính để chọn match thay vì chuỗi if/else if khi giá trị là một kiểu tổng.

Biến thể enum trong Zero có thể mang giá trị đi kèm không?

Không, đó là việc của choice. enum được cố tình giữ là kiểu tổng tối giản: mỗi biến thể chỉ là một nhãn. Nếu bạn cần gắn một i32 hoặc một String vào một biến thể, bạn đã vượt quá enum và cần một choice.

Khi nào nên dùng enum trong Zero?

Dùng enum khi một giá trị phải là đúng một trong một tập nhỏ các trạng thái có tên và các trạng thái đó không mang dữ liệu thêm. Ví dụ: ngày trong tuần, màu đèn giao thông, trạng thái vòng đời không có metadata, mức độ log. Nếu bạn thấy mình muốn gắn dữ liệu vào một biến thể, hãy chuyển sang choice.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu