Sự khác biệt giữa các toán tử gán =
và <-
trong R là gì?
Như ví dụ của bạn cho thấy, =
và <-
có quyền ưu tiên toán tử hơi khác nhau (xác định thứ tự đánh giá khi chúng được trộn trong cùng một biểu thức). Trong thực tế, ?Syntax
trong R đưa ra bảng ưu tiên toán tử sau, từ cao nhất đến thấp nhất:
…
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)
…
Nhưng đây có phải là sự khác biệt duy nhất?
Vì bạn đã hỏi về các toán tử gán : có, đó là sự khác biệt duy nhất. Tuy nhiên, bạn sẽ được tha thứ vì tin vào điều khác. Ngay cả tài liệu R về ?assignOps
tuyên bố rằng có nhiều khác biệt:
Toán tử <-
có thể được sử dụng ở bất cứ đâu, trong khi toán tử =
chỉ được phép ở cấp cao nhất (ví dụ: trong biểu thức hoàn chỉnh được gõ tại dấu nhắc lệnh) hoặc là một trong các biểu thức con trong danh sách các biểu thức được giằng.
Chúng ta đừng đặt quá nhiều điểm vào đó: tài liệu R là (tinh tế) sai [ 1 ] . Điều này rất dễ để hiển thị: chúng ta chỉ cần tìm một ví dụ ngược lại của =
toán tử không (a) ở cấp cao nhất, cũng không (b) một biểu thức con trong danh sách các biểu thức (ví dụ {…; …}
). - Không cần quảng cáo thêm:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Rõ ràng chúng tôi đã thực hiện một nhiệm vụ, sử dụng =
, bên ngoài bối cảnh (a) và (b). Vậy, tại sao tài liệu về tính năng ngôn ngữ R cốt lõi bị sai trong nhiều thập kỷ?
Đó là bởi vì trong cú pháp của R, biểu tượng =
có hai ý nghĩa riêng biệt thường xuyên bị xáo trộn:
- Ý nghĩa đầu tiên là như một toán tử gán . Đây là tất cả những gì chúng ta đã nói về cho đến nay.
- Ý nghĩa thứ hai không phải là một toán tử mà là một mã thông báo cú pháp báo hiệu các đối số được đặt tên trong một lệnh gọi hàm. Không giống như
=
toán tử, nó thực hiện không có hành động nào trong thời gian chạy, nó chỉ thay đổi cách biểu thức được phân tích cú pháp.
Hãy xem nào.
Trong bất kỳ đoạn mã nào có dạng chung
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... những =
là dấu hiệu rằng định nghĩa tên tham số đi qua: đó là không toán tử gán. Hơn nữa, =
hoàn toàn bị cấm trong một số bối cảnh cú pháp:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Bất kỳ điều nào trong số này cũng sẽ gây ra lỗi không mong đợi '=' trong trò chơi blas Đá.
Trong bất kỳ bối cảnh nào khác, =
đề cập đến cuộc gọi toán tử gán. Cụ thể, chỉ cần đặt dấu ngoặc đơn xung quanh biểu thức con sẽ làm cho bất kỳ điều nào ở trên (a) hợp lệ và (b) một bài tập . Ví dụ, các nhiệm vụ sau đây thực hiện nhiệm vụ:
median((x = 1 : 10))
Nhưng cũng:
if (! (nf = length(from))) return()
Bây giờ bạn có thể phản đối rằng mã đó là tàn bạo (và bạn có thể đúng). Nhưng tôi đã lấy mã này từ base::file.copy
hàm (thay thế <-
bằng =
) - đó là một mẫu phổ biến trong phần lớn cơ sở mã R lõi.
Giải thích ban đầu của John Chambers , mà tài liệu R có thể dựa trên, thực sự giải thích điều này một cách chính xác:
[ =
gán được] chỉ được phép ở hai vị trí trong ngữ pháp: ở cấp cao nhất (dưới dạng một chương trình hoàn chỉnh hoặc biểu thức do người dùng nhập); và khi bị cô lập khỏi cấu trúc logic xung quanh, bằng dấu ngoặc hoặc thêm một cặp dấu ngoặc đơn.
Một lời thú nhận: Tôi đã nói dối sớm hơn. Có là một sự khác biệt thêm giữa =
và <-
các nhà khai thác: họ gọi là chức năng riêng biệt. Theo mặc định, các hàm này thực hiện tương tự nhưng bạn có thể ghi đè một trong hai hàm riêng biệt để thay đổi hành vi. Ngược lại, <-
và ->
(gán từ trái sang phải), mặc dù khác biệt về mặt cú pháp, luôn gọi cùng một hàm. Ghi đè cái này cũng ghi đè cái kia. Biết điều này hiếm khi thực tế nhưng nó có thể được sử dụng cho một số shenanigans vui vẻ .
<-
biểu tượng đến từ bàn phím APL cũ thực sự có một<-
phím duy nhất trên chúng.