Nhiều ngôn ngữ chọn cách thực hiện gán một câu lệnh thay vì một biểu thức, bao gồm cả Python:
foo = 42 # works
if foo = 42: print "hi" # dies
bar(foo = 42) # keyword arg
và Golang:
var foo int
foo = 42 # works
if foo = 42 { fmt.Printn("hi") } # dies
Các ngôn ngữ khác không có sự phân công, nhưng các ràng buộc trong phạm vi, ví dụ OCaml:
let foo = 42 in
if foo = 42 then
print_string "hi"
Tuy nhiên, let
là một biểu hiện chính nó.
Ưu điểm của việc cho phép gán là chúng ta có thể kiểm tra trực tiếp giá trị trả về của hàm bên trong điều kiện, ví dụ như trong đoạn Perl này:
if (my $result = some_computation()) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
Perl cũng bổ sung phạm vi khai báo vào điều kiện duy nhất, điều này làm cho nó rất hữu ích. Nó cũng sẽ cảnh báo nếu bạn gán bên trong một điều kiện mà không khai báo một biến mới ở đó - if ($foo = $bar)
sẽ cảnh báo, if (my $foo = $bar)
sẽ không.
Việc chuyển nhượng trong một tuyên bố khác thường là đủ, nhưng có thể mang lại các vấn đề phạm vi:
my $result = some_computation()
if ($result) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
# $result is still visible here - eek!
Golang phụ thuộc rất nhiều vào các giá trị trả về để kiểm tra lỗi. Do đó, nó cho phép một điều kiện để đưa ra một tuyên bố khởi tạo:
if result, err := some_computation(); err != nil {
fmt.Printf("Failed with %d", result)
}
fmt.Printf("We succeeded, and the result is %d\n", result)
Các ngôn ngữ khác sử dụng một hệ thống loại để không cho phép các biểu thức không phải là boolean bên trong một điều kiện:
int foo;
if (foo = bar()) // Java does not like this
Tất nhiên điều đó không thành công khi sử dụng hàm trả về boolean.
Bây giờ chúng ta đã thấy các cơ chế khác nhau để bảo vệ chống lại sự phân công tình cờ:
- Không cho phép chuyển nhượng như một biểu thức
- Sử dụng kiểm tra kiểu tĩnh
- Chuyển nhượng không tồn tại, chúng tôi chỉ có
let
ràng buộc
- Cho phép một câu lệnh khởi tạo, không cho phép chuyển nhượng
- Không cho phép chuyển nhượng trong một điều kiện mà không cần khai báo
Tôi đã xếp chúng theo thứ tự ưu tiên tăng dần - các phép gán bên trong các biểu thức có thể hữu ích (và thật đơn giản để tránh các vấn đề của Python bằng cách sử dụng cú pháp khai báo rõ ràng và cú pháp đối số có tên khác). Nhưng không được phép không cho phép họ, vì có nhiều lựa chọn khác cho cùng một hiệu ứng.
Mã không có lỗi quan trọng hơn mã terse.