Một cách duy nhất để đặt tên cho giá trị
Trong Zero, bạn đặt tên cho một giá trị bằng let:
let answer = 42
Cú pháp chỉ có vậy. Không có var, không có const, không có auto. Chỉ một từ khóa binding giúp ngôn ngữ luôn nhỏ gọn: cả agent lẫn con người chỉ cần học một lần rồi áp dụng ở mọi nơi.
let tạo một binding cục bộ trong phạm vi (scope) hiện tại. Sau dòng này, answer trỏ tới 42 cho đến hết khối lệnh bao quanh.
Suy luận kiểu
Trình biên dịch suy luận kiểu từ vế phải. Literal 42 mặc định có kiểu i32, nên answer là một i32. Literal "hello" là một chuỗi, nên:
let greeting = "hello"
gắn greeting với một giá trị chuỗi. Nếu bạn gọi một hàm trả về Pair<i32, u8>, binding sẽ có kiểu Pair<i32, u8>:
let pair = makePair(40, 2_u8)
Bạn không phải ghi kiểu cho mọi binding, nhờ vậy code luôn dễ đọc.
Chú thích kiểu tường minh
Khi bạn muốn ghi rõ kiểu, hoặc ép một kiểu cụ thể khi suy luận sẽ chọn kiểu khác, hãy viết kiểu sau dấu hai chấm:
let count: u8 = 10
let pair: Pair<i32, u8> = makePair(40, 2_u8)
Chú thích kiểu cũng là gợi ý cho trình biên dịch khi một literal có thể thuộc nhiều kiểu. Literal 10 có thể là i32, i64, u8, v.v.; chú thích kiểu sẽ chốt lại kiểu nào.
Bạn cũng sẽ gặp hậu tố kiểu trên literal, một cách thay thế cho việc chú thích kiểu trên binding:
let small = 10_u8 // u8 from the literal suffix
let big = 10_i64 // i64 from the literal suffix
Cả hai dạng đều hợp lệ. Hãy chọn dạng nào thể hiện ý định rõ nhất tại chỗ viết code.
Binding trong thực tế
Một ví dụ hoàn chỉnh dùng cả dạng suy luận lẫn dạng tường minh. Nhấn Chạy để thử:
point được chú thích kiểu tường minh vì vế phải là một literal struct. total được suy luận: sum được khai báo trả về i32, nên binding cũng là i32.
Phạm vi và shadowing
Một binding let có hiệu lực từ dòng khai báo nó đến hết khối lệnh bao quanh. Các khối lồng nhau tạo ra phạm vi mới:
pub fun main(world: World) -> Void raises {
let value = 1
if true {
let value = 2 // shadows the outer 'value' inside this block
// here, value == 2
}
// back outside the if, value == 1 again
}
value bên trong không thay đổi value bên ngoài. Đó là một binding riêng, ra khỏi phạm vi tại dấu ngoặc nhọn đóng của khối if. Đây cũng là mô hình của Rust và các ngôn ngữ họ ML. Cách này đặc biệt hay dùng khi bạn muốn biến đổi một giá trị qua nhiều bước mà không phải nghĩ tên mới cho từng kết quả trung gian.
Những gì let không làm
Một vài thứ bạn có thể quen ở ngôn ngữ khác nhưng let cố ý không có:
- Khai báo chỉ có kiểu. Không có dạng
let x: i32;để tạo binding chưa khởi tạo. Một binding phải có giá trị ngay tại chỗ khai báo. - Destructuring theo mẫu (chưa có). Một số ngôn ngữ cho phép viết
let (a, b) = pair. Zero được thiết kế nhỏ gọn và hiện tập trung vào binding tên đơn giản. Hãy xem tài liệu mới nhất để biết destructuring đã có hay chưa. - Nhiều từ khóa cho các vòng đời khác nhau. Không có
static,const,let mutriêng, cũng không có biến thể theo phạm vi khối hay phạm vi hàm. Chỉ một từ khóa.
Nếu bạn đến từ JavaScript, thứ gần nhất là const: một tên gắn với một giá trị cho đến hết khối, có shadowing trong các phạm vi bên trong. Nếu bạn đến từ Rust, let ở đây đóng vai trò giống let của Rust, chỉ là không có từ khóa mut tường minh.
Một mẫu hay dùng: xây dựng giá trị từng bước
Binding phát huy tác dụng khi bạn muốn viết một phép tính thành chuỗi các bước trung gian có tên. Cách này tốt cho cả người đọc lẫn agent khi suy luận cục bộ về từng dòng:
Mỗi dòng đưa vào một dữ kiện mới để phần còn lại của hàm sử dụng. Trình biên dịch vẫn tạo ra code gọn: đặt tên cho các giá trị trung gian không tốn chi phí gì lúc chạy.
Tiếp theo: kiểu nguyên thủy
let chẳng có mấy ý nghĩa nếu không có gì để gắn. Tài liệu tiếp theo đi qua các kiểu nguyên thủy của Zero: các độ rộng số nguyên, số thực, chuỗi, cùng hai kiểu Void và Bool mà bạn sẽ gặp thường xuyên nhất.
Câu hỏi thường gặp
Khai báo biến trong Zero như thế nào?
Dùng let. Dạng let name = value để trình biên dịch tự suy luận kiểu, hoặc let name: Type = value để ghi rõ kiểu. Ví dụ: let answer = 42 hoặc let answer: i32 = 42. Cả hai đều gắn tên answer với giá trị 42 trong phạm vi hiện tại.
Zero có tự suy luận kiểu cho binding let không?
Có. Nếu bạn viết let total = sum(point) và sum trả về i32, kiểu của binding được suy luận là i32. Bạn vẫn có thể chú thích kiểu tường minh khi muốn ghi lại kiểu hoặc ép một kiểu cụ thể, ví dụ let count: u8 = 10.
Binding let trong Zero có thay đổi được không?
let thông thường tạo một binding cục bộ để dùng trong phạm vi của nó. Cách Zero trước bản 1.0 xử lý khả năng thay đổi (mutability) vẫn đang được hoàn thiện. Ngôn ngữ này đề cao hiệu ứng tường minh và bộ nhớ dễ đoán, nên mọi thao tác thay đổi trạng thái qua một binding đều phải thể hiện rõ ràng. Hãy xem tài liệu Zero mới nhất để biết cú pháp chính xác cho phiên bản toolchain bạn đang dùng.
let và const trong Zero khác nhau thế nào?
Zero dùng let cho các binding cục bộ thông thường trong thân hàm. Zero không có nhiều từ khóa binding như let/const/var của JavaScript, vì giữ cho ngôn ngữ nhỏ gọn là một lựa chọn thiết kế có chủ ý. Hằng số lúc biên dịch thường được biểu diễn qua hệ thống kiểu hoặc các khai báo ở cấp cao nhất, không qua một từ khóa riêng.
Có thể khai báo lại một binding let trong Zero không?
Binding tồn tại trong phạm vi bao quanh nó. Một let mới cùng tên trong phạm vi lồng nhau là một binding riêng, che khuất (shadowing) binding bên ngoài trong suốt phạm vi bên trong. Binding bên ngoài không bị ảnh hưởng khi phạm vi bên trong kết thúc. Đây cũng là mô hình mà Rust và các ngôn ngữ họ ML sử dụng.