Cơ bản
while chạy thân của nó chừng nào một điều kiện bool còn là true:
while condition {
// body
}
Trình biên dịch tính điều kiện trước mỗi lần lặp:
true: chạy thân vòng lặp, rồi kiểm tra lại.false: thoát khỏi vòng lặp.
Một ví dụ đơn giản từ các ví dụ của Zero, với điều kiện ngay từ đầu đã là false:
Chạy đoạn code này thì chỉ lệnh write thứ hai được thực thi. Thân của while không bao giờ chạy vì điều kiện đã là false ngay lần kiểm tra đầu tiên.
Điều kiện là một bool
Giống như với if/else, điều kiện của vòng lặp phải là một bool. Zero không tự chuyển số nguyên, chuỗi hay các giá trị khác thành boolean.
while count { // compile error
// ...
}
while count > 0 { // OK
// ...
}
Điều kiện có thể là bất cứ thứ gì cho ra bool: một binding, một phép so sánh, một tổ hợp &&/|| hoặc một lời gọi hàm. Các quy tắc giống hệt như với if.
Vòng lặp có đếm
Mẫu kinh điển "làm việc gì đó N lần" dùng một biến đếm và một while:
let mut i = 0
while i < 10 {
// do work
i = i + 1
}
Ba thành phần: một giá trị khởi đầu, một điều kiện so sánh với giới hạn, và một bước cập nhật trong thân vòng lặp. Đây là mẫu mà mọi ngôn ngữ mệnh lệnh đều có; Zero chỉ không khoác cho nó từ khóa for.
Lưu ý về cách viết mut ở trên: cách Zero viết binding có thể thay đổi trong toolchain của bạn có thể khác ở các phiên bản trước 1.0. Hãy chạy zero check --json trên một ví dụ nhỏ để xác nhận cú pháp chính xác mà trình biên dịch của bạn chấp nhận. Phần ổn định là mẫu ý tưởng (biến đếm + điều kiện + cập nhật).
Vòng lặp vô hạn
Một while có điều kiện luôn là true sẽ chạy mãi mãi:
while true {
// wait for work, handle it, loop again
}
Đây là hình dạng phù hợp cho một vòng lặp sự kiện, một REPL hay một máy chủ chạy lâu dài. Để thoát, bạn có thể kết thúc tiến trình, ném một lỗi ra khỏi thân vòng lặp, hoặc cấu trúc lại để điều kiện trở thành sai.
Khi nào nên dùng vòng lặp
Vòng lặp là công cụ nên dùng có chừng mực. Những thứ trông như vòng lặp ở ngôn ngữ khác thường có dạng gọn hơn trong Zero:
- Duyệt qua một tập hợp cố định: ưu tiên một hàm mà thư viện chuẩn hoặc shape của bạn cung cấp, như một hàm hỗ trợ kiểu
forEach, một hàm fold, hoặc một phép duyệt đệ quy. - Đọc cho đến hết đầu vào: lặp trên một thao tác đọc có thể thất bại, nhưng dùng
checkvàraisesđể xử lý điểm kết thúc gọn gàng thay vì lồng các cờ trạng thái. - Chờ một điều kiện xảy ra (polling): hãy cân nhắc liệu thiết kế có nên trao cho bạn một tín hiệu thay vào đó không. Vòng lặp polling là dấu hiệu code có vấn đề trong bất kỳ ngôn ngữ hệ thống nào.
Cùng một bản năng đó cũng đúng với agent: một dạng gọn, mang tính khai báo dễ suy luận hơn một vòng lặp đếm viết tay, cho cả con người lẫn công cụ sinh code.
Vòng lặp và hiệu ứng
Thân của một while, như mọi khối lệnh khác, có thể thực hiện I/O, nhưng chỉ khi nó có quyền truy cập một capability World (hoặc một phần của nó). Một hàm mà chữ ký không nhắc đến World có thể lặp bao nhiêu tùy thích nhưng không thể ghi gì ra bên ngoài. Đặc tính đó cũng đúng bên trong thân vòng lặp; vòng lặp không cấp thêm capability nào mới.
Nghe thì hiển nhiên, nhưng đó chính là lý do bạn có thể đặt một while bên trong một hàm tính toán "thuần" mà vẫn biết, chỉ từ chữ ký, rằng nó không thể in ra gì hay ghi gì xuống đĩa.
Lưu ý về phong cách
Vài thói quen nhỏ mang lại lợi ích:
- Giữ điều kiện dễ hiểu. Nếu điều kiện đang làm việc thực sự, hãy tách nó thành một hàm hoặc binding có tên để vòng lặp đọc cho gọn.
- Cập nhật biến đếm ở cuối thân vòng lặp, đừng rải rác khắp nơi. Như vậy dễ phát hiện lỗi lệch một đơn vị (off-by-one) hơn.
- Ưu tiên các điều kiện thoát sớm mà bạn có thể diễn đạt bằng chính điều kiện của vòng lặp, thay vì các cờ đổi giá trị giữa lần lặp. Ít thành phần thay đổi hơn.
Tiếp theo: shape
Bạn đã thấy luồng điều khiển cốt lõi của Zero. Chương tiếp theo nói về mô hình hóa dữ liệu, bắt đầu với shape, kiểu tích giống struct của Zero.
Câu hỏi thường gặp
Vòng lặp while trong Zero hoạt động như thế nào?
Dùng while condition { ... }. Điều kiện được tính trước mỗi lần lặp; nếu là true, thân vòng lặp chạy rồi vòng lặp kiểm tra lại. Nếu là false, vòng lặp kết thúc và chương trình chạy tiếp sau dấu ngoặc nhọn đóng. Điều kiện phải là một bool.
Zero có vòng lặp for không?
Phiên bản đầu của Zero chỉ có while là cấu trúc vòng lặp duy nhất. Ngôn ngữ cố ý giữ bề mặt nhỏ trong lúc ổn định dần: ít từ khóa hơn nghĩa là agent ít có cơ hội chọn sai dạng hơn. Vòng lặp for trên một khoảng hay một tập hợp có thể sẽ có sau này; trước đó, bạn viết cùng mẫu đó bằng while và một biến đếm.
Viết vòng lặp có đếm trong Zero như thế nào?
Khởi tạo một biến đếm, chạy while theo biến đó và cập nhật nó trong thân vòng lặp: let mut i = 0; while i < 10 { ...; i = i + 1 }. Cú pháp cho khả năng thay đổi vẫn đang được hoàn thiện ở Zero trước bản 1.0, nên hãy xem tài liệu hiện tại để biết cách viết chính xác. Dù vậy, mẫu while + biến đếm + cập nhật là cách viết chuẩn cho vòng lặp có đếm.
Zero có break hay continue không?
Hầu hết các ngôn ngữ cùng họ với Zero đều có một cấu trúc thoát sớm khỏi vòng lặp; cách viết chính xác trong Zero là một trong những phần có thể thay đổi trước bản 1.0. Cách làm an toàn là cấu trúc vòng lặp sao cho chính điều kiện làm việc đó: đảo ngược và cập nhật điều kiện để vòng lặp tự kết thúc, thay vì dựa vào một từ khóa điều khiển luồng cụ thể.
Vòng lặp while trong Zero có thể chạy mãi mãi không?
Có. while true { ... } là một vòng lặp vô hạn. Nó hữu ích cho máy chủ, vòng lặp sự kiện, REPL, bất cứ thứ gì không có điều kiện kết thúc tự nhiên. Khác với việc ngầm hiểu giá trị là đúng hay sai, true ở đây là một literal kiểu bool nên điều kiện vẫn đúng kiểu.