Hãy thử suy nghĩ về "kỳ vọng" của thông dịch viên, và nhớ rằng trong ruby EVERYTHING là một biểu thức (có nghĩa là mọi thứ đều đánh giá một giá trị nào đó, thậm chí xây dựng bằng ngôn ngữ khác được coi là "đặc biệt" -elses, vòng lặp, etcettera).
Vì vậy:
y = ( #1
a #2
+ b #3
)/ #4
2 #5
Tại dòng 1, chúng tôi bắt đầu khai báo của một biến, và dòng kết thúc với một mở (pending) ngoặc. Trình thông dịch mong đợi phần còn lại của định nghĩa, vì vậy nó sẽ chuyển sang dòng tiếp theo tìm kiếm giá trị VALUE để gán cho var y
.
Tại dòng 2, thông dịch viên tìm biến số a
, nhưng không có dấu ngoặc đơn kèm theo. Nó đánh giá a
, có giá trị 5
và vì dòng 2 là một biểu thức hoàn toàn hợp lệ, trình thông dịch hiểu rằng biểu thức này đã hoàn thành (vì trong Ruby một dòng mới OFTEN có nghĩa là chỉ báo cuối biểu thức). Vì vậy, cho đến nay nó đã tạo ra một giá trị 5
, nhưng kỳ vọng duy nhất nó vẫn có là nó phải khớp với dấu ngoặc đơn kèm theo.
Nếu sau đó thông dịch viên đã tìm thấy dấu ngoặc đơn kèm theo, nó sẽ gán giá trị a (i.e. 5)
cho biểu thức dấu ngoặc đơn (vì mọi thứ phải có giá trị và giá trị cuối cùng được sử dụng).
Khi thông dịch viên đạt đến dòng 3, nó tìm thấy một biểu thức ruby hoàn toàn hợp lệ khác, + b
. Kể từ + 5
(5
là giá trị biến số b
) là một khai báo số nguyên VALID trong ruby, trình thông dịch coi nó là độc lập, không liên quan đến số 5
trước đó được đánh giá cho biến a
(hãy nhớ, nó không có kỳ vọng khác, ngoại trừ một cho dấu ngoặc đơn). Nói ngắn gọn, nó sẽ lấy đi giá trị thu được cho a
và chỉ sử dụng giá trị thu được với + b
. Trong dòng tiếp theo, nó tìm thấy dấu ngoặc đơn kèm theo, và do đó biểu thức dấu ngoặc đơn được gán giá trị được tạo cuối cùng, là một 5
được tạo ra bởi biểu thức + b
.
Vì trên dòng 4 người thông dịch tìm thấy /
, nó (chính xác) hiểu nó như là phương pháp chia của một số nguyên, vì nó đã tạo ra một số nguyên đến nay (int 5
)! Điều này tạo ra kỳ vọng cho các đối số có thể có của phương thức, mà nó tìm thấy trên dòng 5. Biểu thức được đánh giá kết quả là y = 5/2
, bằng 2
trong phân chia số nguyên. Vì vậy, về cơ bản, đây là những gì người phiên dịch đã làm:
y = ( # Ok, i'm waiting for the rest of the parenthesis expression
a # cool, a has value 5, if the parenthesis ends here, this is the value of the expr.
+ b # Oh, but now I found + b, which has value + 5, which evaluates to 5. So now this is the last value I have evaluated.
)/ # Ok, the parenthesis have been closed, and the last value I had was a 5. Uow, wait, there is a slash/there! I should now wait for another argument for the/method of the 5 I have!
2 # Found, let's make y = 5/2 = 2!
Vấn đề ở đây là trên đường dây # 2, bạn nên đã để lại một kỳ vọng cho người phiên dịch (chính xác như bạn còn lại trên dòng 4 với phương pháp /
) , mà bạn đã không!
Câu trả lời của @ Maurício Linhares gợi ý chính xác này:
y = (
a +
b
)/
2
Bằng cách di chuyển phương pháp +
đến cuối dòng 2, bạn nói với người phiên dịch rằng biểu hiện của bạn vẫn chưa hoàn thành! Vì vậy, nó giữ mong đợi và tiến tới dòng # 3 để tìm toán hạng đúng của biểu thức (hoặc, chính xác hơn trong Ruby, một đối số cho phương thức +
: D).
Các công trình tương tự với chuỗi nối:
# WRONG, SINCE + "somestring" is not a valid stand-alone expression in ruby
str = "I like to"
+ " move it!"
# NoMethodError: undefined method `[email protected]' for " move it!":String
# CORRECT, by leaving the + sign as last statement of the first line, you
# keep the 'expectation' of the interpreter for the next
# argument of the + method of the string object "I like to"
str = "I like to" +
" move it!"
# => "I like to move it!"
Sự khác biệt là trong mã của bạn không có lỗi ném, vì + b thực sự là một biểu thức hợp lệ.
Tôi hy vọng câu trả lời của tôi hữu ích khi mang lại cho bạn một số trực giác tại sao nó không hoạt động như mong đợi, xin lỗi nếu tôi không súc tích :)
không có ngoại lệ, // dấu nhận xét là sai, xin lỗi, nó chỉ để làm rõ đầu ra của chương trình. Đã chỉnh sửa. Cảm ơn bạn đã sửa. – waza