Viết tệp
Mở editor và lưu năm dòng sau thành hello.0 ở chỗ nào tiện, hoặc chỉ cần nhấn Chạy ở khối bên dưới:
Vậy là xong, một chương trình Zero hoàn chỉnh. Để chạy nó trên máy của bạn:
zero run hello.0
Bạn sẽ thấy:
hello from zero
Nếu bạn gặp command not found, hãy quay lại Cài đặt Zero và đảm bảo zero --version chạy được trước đã.
Mổ xẻ từng token
Ngay cả chương trình nhỏ xíu này cũng đã cho thấy phần lớn những gì làm Zero khác biệt. Cùng đọc từ trái sang phải.
pub
pub đánh dấu một khai báo là công khai: nhìn thấy được từ bên ngoài module hiện tại. Runtime cần tìm main từ bên ngoài phạm vi riêng của tệp, nên main phải là pub. Một hàm phụ riêng tư trong cùng tệp thì không cần.
fun
fun mở đầu một khai báo hàm. Zero dùng fun, không phải fn (Rust), func (Go) hay function (JavaScript). Một từ khóa, lần nào cũng dùng theo cùng một cách.
main
Tên điểm vào theo quy ước. Khi một target thực thi của Zero chạy, runtime tìm pub fun main(world: World) và gọi nó. Bạn đặt tên các hàm khác thế nào cũng được, nhưng main được dành riêng theo quy ước cho điểm vào của chương trình.
(world: World)
Tham số duy nhất tên là world và có kiểu World. Runtime tạo một giá trị World trước khi gọi main rồi truyền nó vào. Giá trị đó mang các capability của chương trình: quyền truy cập stdout, stdin, hệ thống tệp, mạng, v.v., tùy vào những gì runtime quyết định cấp.
Tên tham số do bạn chọn: (w: World) hay (io: World) đều biên dịch bình thường. Quy ước trong các ví dụ là world, và chúng ta sẽ giữ tên đó.
-> Void
Kiểu trả về. Void nghĩa là hàm không trả về gì hữu ích: nó tồn tại vì hiệu ứng phụ, không phải vì giá trị. Nhiều hàm bạn viết sẽ trả về kiểu thật như i32 hoặc một shape do bạn định nghĩa.
raises
raises đứng một mình (không có kiểu lỗi cụ thể) trên main nói rằng "hàm này có thể thất bại". Với main, điều đó nghĩa là chương trình có thể thoát với mã trạng thái khác 0 nếu bất kỳ check nào trong thân hàm lan truyền lỗi lên. Chúng ta sẽ thấy các dạng hẹp hơn, ví dụ raises { InvalidInput }, trong Raises và check.
check world.out.write("hello from zero\n")
Đây là dòng thực sự làm việc. Ba phần nhỏ:
world.out: luồng đầu ra chuẩn, được cung cấp như một trường trên capabilityWorld..write("hello from zero\n"): một phương thức ghi chuỗi vào luồng đó. Nó trả về một kết quả có thể báo thất bại (việc ghi có thể lỗi; luồng có thể đã đóng).check: lan truyền thất bại đó lên nếu nó xảy ra. Không cócheck, trình biên dịch sẽ phàn nàn rằng kết quả củawriteđang bị bỏ qua âm thầm.
\n ở cuối là một ký tự xuống dòng. Không có nó, đầu ra sẽ không xuống dòng mới và dấu nhắc của shell sẽ nằm chung dòng với thông điệp của bạn.
Điều gì vừa xảy ra
Khi bạn chạy zero run hello.0:
- Trình biên dịch phân tích cú pháp tệp và kiểm tra kiểu.
- Nó tạo ra một tệp thực thi native nhỏ cho nền tảng của bạn.
- Runtime tạo một capability
Worldcho tiến trình hiện tại. - Nó gọi
main(world). - Code của bạn ghi "hello from zero\n" vào luồng
outcủa world đó, vốn được nối với stdout của terminal. maintrả vềVoid, runtime dọn dẹp, và chương trình thoát với mã trạng thái 0.
Không có bộ thu gom rác, không có khởi tạo runtime ẩn, không có bước khởi động module ngầm. Toàn bộ chương trình là hàm bạn đã viết, cộng với code thư viện chuẩn mà nó gọi.
Thử một thay đổi nhỏ
Cho chương trình gán thông điệp vào một biến trước khi ghi:
Chạy lại: đầu ra vẫn vậy, nhưng giờ bạn đã thấy biến let và xác nhận rằng chuỗi là giá trị hạng nhất mà bạn có thể truyền đi khắp nơi.
Một phiên bản lỗi
Chuyện gì xảy ra nếu bạn quên check?
pub fun main(world: World) -> Void raises {
world.out.write("oops\n")
}
zero check hello.0 sẽ từ chối biên dịch đoạn này. Kết quả của write là một giá trị có thể thất bại; bỏ qua nó là lỗi biên dịch. Bạn hoặc check nó (lan truyền lỗi), hoặc xử lý nó tường minh. Đây là cùng ý tưởng với các kết quả must_use của Rust, chỉ có điều được bắt buộc với mọi lời gọi có thể thất bại.
Tiếp theo: Zero CLI
Ở đây bạn đã dùng zero run. CLI có một nhóm nhỏ các lệnh đáng biết, check, run, build, test, fix, explain, mỗi lệnh đều có chế độ --json có cấu trúc, được thiết kế để agent sử dụng.
Câu hỏi thường gặp
Chương trình hello world trong Zero là gì?
Hello world chuẩn của Zero gồm năm dòng: pub fun main(world: World) -> Void raises { check world.out.write("hello from zero\n") }. Lưu nó thành hello.0 rồi chạy zero run hello.0.
pub fun main trong Zero nghĩa là gì?
pub làm cho một khai báo thành công khai: nhìn thấy được từ bên ngoài module. fun khai báo một hàm. main là điểm vào quen thuộc mà Zero tìm trong một target thực thi. Gộp lại, pub fun main khai báo điểm vào công khai mà runtime gọi khi chương trình bắt đầu.
Vì sao main nhận một tham số World?
Zero không có I/O toàn cục. Mọi thứ giao tiếp với thế giới bên ngoài, như stdout, stdin, tệp, mạng, đều đi qua các capability được truyền vào tường minh. Runtime trao cho main một giá trị World, và giá trị đó (hoặc các phần của nó) là cách duy nhất để hàm làm I/O. Điều này khiến hiệu ứng phụ hiện rõ trong chữ ký hàm.
raises và check làm gì trong hello world?
raises trên main khai báo rằng hàm có thể thất bại. check world.out.write(...) gọi một hàm có thể thất bại và, nếu nó thất bại, lan truyền lỗi lên nơi gọi: ở đây là runtime, và chương trình thoát với mã trạng thái khác 0. Không có check, trình biên dịch sẽ từ chối biên dịch lời gọi vì lỗi chưa được xử lý.
Zero dùng phần mở rộng tệp nào?
Tệp mã nguồn Zero dùng phần mở rộng .0 (chữ số không, không phải chữ O). Tệp hello.0 là một tệp mã nguồn Zero. Trình biên dịch được gọi bằng các lệnh như zero check hello.0 và zero run hello.0.