Menu

If/else trong Zero: giải thích câu lệnh rẽ nhánh

Cách if và else hoạt động trong Zero: điều kiện boolean, thân nhánh, không có ép kiểu truthy, và cách câu lệnh điều kiện kết hợp với match để rẽ nhánh phong phú hơn.

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.

Cơ bản

if trong Zero trông gần giống if trong mọi ngôn ngữ họ C khác, với một hạn chế đáng chú ý: điều kiện phải là một bool.

Điều kiện value == 42 là một bool vì == giữa hai i32 trả về bool. Mỗi nhánh chứa một khối lệnh. Có thể bỏ bớt một nhánh, vì else là tùy chọn, nhưng khi có cả hai thì cả hai đều phải là khối { ... }.

Yêu cầu về bool

Một số ngôn ngữ cho phép viết if value { ... } và coi 0, "" hay null là falsy. Zero thì không. Điều kiện phải là một bool thực sự.

let count = 0
if count {              // compile error: expected bool, got i32
    // ...
}

if count == 0 {         // OK
    check world.out.write("nothing to do\n")
}

Lý do cũng chính là tinh thần xuyên suốt cả ngôn ngữ: tường minh tốt hơn ngầm định. Một agent đọc dạng thứ hai biết chính xác điều gì đang được kiểm tra. Dạng thứ nhất để các quy tắc truthy ở trạng thái ngầm định, và chúng khác nhau giữa các ngôn ngữ: Zero chọn không tham gia.

Else và else if

Mệnh đề else chạy khi điều kiện là false:

Nối các điều kiện bằng else if:

if value < 0 {
    check world.out.write("negative\n")
} else if value == 0 {
    check world.out.write("zero\n")
} else {
    check world.out.write("positive\n")
}

else if chỉ là else { if ... } bỏ bớt dấu ngoặc nhọn: cùng ngữ nghĩa, ít thụt lề hơn. else cuối cùng là tùy chọn.

Điều kiện đến từ đâu

Điều kiện có thể là bất cứ thứ gì cho ra bool:

  • Một biến bool: if ok { ... }.
  • Một phép so sánh: if value == 42 { ... }, if x < y { ... }.
  • Một tổ hợp logic: if a && b { ... }, if pair.left == 1_u8 && pair.right == 2_u8 { ... }.
  • Một lời gọi hàm trả về bool: if isReady(world) { ... }.

Một đoạn code thực tế từ các ví dụ của ngôn ngữ:

let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
if pair.left == 1_u8 && pair.right == 2_u8 {
    check world.out.write("type alias ok\n")
} else {
    check world.out.write("type alias broke\n")
}

&& đánh giá ngắn mạch đúng như bạn mong đợi: nếu vế trái là false, vế phải sẽ không được tính. || cũng vậy.

Khi nào nên dùng match

Chuỗi if/else if ổn cho các quyết định hai hoặc ba hướng, nhất là khi các điều kiện không có cấu trúc chung. Nhưng khi bạn rẽ nhánh theo các biến thể của một kiểu tổng, một choice hoặc enum, thì match mới là công cụ đúng.

So sánh:

// match - exhaustive, compiler-checked
match result {
    .ok  => value   { check world.out.write("ok\n") }
    .err => message { check world.out.write("err\n") }
}

với:

// if/else over a sum type - verbose and easier to get wrong
if result.isOk() {
    let value = result.unwrap()
    check world.out.write("ok\n")
} else {
    check world.out.write("err\n")
}

Dạng match làm cho việc phân tích biến thể trở nên tường minh, và trình biên dịch sẽ báo lỗi nếu sau này có biến thể mới mà bạn quên xử lý. Dạng if âm thầm cho mọi thứ không phải ok đi vào nhánh else, kể cả những biến thể hoàn toàn mới mà bạn chưa từng nghĩ tới.

Quy tắc nhanh: if cho boolean, match cho biến thể.

Ghi chú về phong cách

Vài quy ước nhỏ giúp code dễ đọc hơn cho cả con người lẫn agent:

  • Luôn đặt thân trong ngoặc nhọn. Kể cả thân chỉ một dòng cũng nằm trong { ... }. Không có dạng một câu lệnh không ngoặc. Điều này là có chủ đích: nó giữ thụt lề đáng tin cậy và loại bỏ một nguồn bug phổ biến trong họ ngôn ngữ C.
  • Đặt nhánh thường gặp nhất lên trước. Người đọc (và agent) lướt từ trên xuống dưới.
  • Ưu tiên điều kiện khẳng định khi chúng rõ ràng như nhau. if isReady dễ theo dõi hơn if !notReady, khi mọi thứ khác là như nhau.

Tiếp theo: vòng lặp while

Câu lệnh điều kiện quyết định làm gì; vòng lặp quyết định làm bao nhiêu lần. Tài liệu tiếp theo trình bày vòng lặp while của Zero, cấu trúc lặp ở giai đoạn đầu mà ngôn ngữ đang cung cấp.

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

Câu lệnh if hoạt động thế nào trong Zero?

Dùng if condition { ... } kèm mệnh đề else { ... } tùy chọn. Điều kiện phải là một bool: Zero không ép số nguyên, chuỗi hay giá trị khác thành boolean. Ví dụ: if value == 42 { check world.out.write("yes\n") } else { check world.out.write("no\n") }.

Zero có toán tử ba ngôi không?

Zero cố tình giữ bề mặt nhỏ và dùng các khối if / else thay vì một toán tử ba ngôi condition ? a : b riêng. Các ví dụ chính thức ưu tiên nhánh tường minh, kể cả với trường hợp ngắn. Nếu ngôn ngữ hỗ trợ if dạng biểu thức, hãy chờ Zero đi theo hướng đó thay vì thêm một cú pháp thứ hai.

Có thể nối chuỗi if/else if trong Zero không?

Có. Nối các điều kiện bằng cách viết else if giữa các nhánh: if a { ... } else if b { ... } else { ... }. Để rẽ nhánh phức tạp hơn theo một choice hoặc enum, hãy dùng match: nó đầy đủ hơn và trình biên dịch kiểm tra rằng bạn đã xử lý mọi biến thể.

Vì sao Zero không ép giá trị thành bool?

Triết lý thiết kế của Zero là 'mọi thứ đều tường minh'. Truthy ngầm, tức là coi 0, "" hay null là false, là nguồn bug thường gặp và khó để agent suy luận chính xác. Yêu cầu một bool thực sự khiến quyết định rẽ nhánh hiện rõ trong mã nguồn và dễ kiểm chứng một cách máy móc hơn.

Khi nào nên dùng match thay vì if/else?

Dùng match khi bạn rẽ nhánh theo các biến thể của một choice hoặc enum. Trình biên dịch có thể kiểm tra rằng bạn đã xử lý mọi trường hợp, điều mà chuỗi if/else if không làm được. Giữ if/else cho các điều kiện boolean đơn giản: so sánh bằng, so sánh lớn nhỏ và rẽ nhánh hai hướng ngắn.

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