Tôi đã cố gắng một lần để viết về điều này, nhưng cuối cùng tôi đã từ bỏ, vì các quy tắc có phần lan tỏa. Về cơ bản, bạn sẽ phải nắm bắt được nó.
Có lẽ tốt nhất là tập trung vào nơi các dấu ngoặc nhọn và dấu ngoặc đơn có thể được sử dụng thay thế cho nhau: khi truyền tham số cho các lệnh gọi phương thức. Bạn có thể thay thế dấu ngoặc đơn bằng dấu ngoặc nhọn nếu và chỉ khi phương thức mong đợi một tham số duy nhất. Ví dụ:
List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter
List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter
Tuy nhiên, có nhiều điều bạn cần biết để nắm bắt tốt hơn các quy tắc này.
Kiểm tra biên dịch tăng với parens
Các tác giả của Spray khuyến nghị parens tròn vì chúng giúp kiểm tra biên dịch tăng lên. Điều này đặc biệt quan trọng đối với DSL như Spray. Bằng cách sử dụng parens, bạn đang nói với trình biên dịch rằng nó chỉ nên được cung cấp một dòng duy nhất; do đó, nếu bạn vô tình cho nó hai hoặc nhiều hơn, nó sẽ phàn nàn. Bây giờ đây không phải là trường hợp với dấu ngoặc nhọn - ví dụ nếu bạn quên một toán tử ở đâu đó, thì mã của bạn sẽ biên dịch và bạn nhận được kết quả không mong muốn và có khả năng là một lỗi rất khó tìm. Dưới đây là kế hoạch (vì các biểu thức là thuần túy và ít nhất sẽ đưa ra cảnh báo), nhưng đưa ra quan điểm:
method {
1 +
2
3
}
method(
1 +
2
3
)
Các biên dịch đầu tiên, thứ hai cho error: ')' expected but integer literal found
. Tác giả muốn viết 1 + 2 + 3
.
Người ta có thể lập luận rằng nó tương tự đối với các phương thức đa tham số với các đối số mặc định; Không thể vô tình quên dấu phẩy để phân tách các tham số khi sử dụng parens.
Độ dài
Một lưu ý quan trọng thường bị bỏ qua về tính dài dòng. Việc sử dụng dấu ngoặc nhọn chắc chắn sẽ dẫn đến mã dài dòng vì hướng dẫn kiểu Scala nói rõ rằng việc đóng dấu ngoặc nhọn phải nằm trên dòng riêng của chúng:
Niềng răng đóng là trên dòng riêng của nó ngay sau dòng cuối cùng của chức năng.
Nhiều trình định dạng lại tự động, như trong IntelliJ, sẽ tự động thực hiện việc định dạng lại này cho bạn. Vì vậy, hãy cố gắng để sử dụng parens tròn khi bạn có thể.
Ký hiệu thông tin
Khi sử dụng ký hiệu infix, như List(1,2,3) indexOf (2)
bạn có thể bỏ dấu ngoặc đơn nếu chỉ có một tham số và viết nó dưới dạng List(1, 2, 3) indexOf 2
. Đây không phải là trường hợp ký hiệu chấm.
Cũng lưu ý rằng khi bạn có một tham số duy nhất là biểu thức nhiều mã thông báo, như x + 2
hoặc a => a % 2 == 0
, bạn phải sử dụng dấu ngoặc đơn để chỉ ra ranh giới của biểu thức.
Bộ dữ liệu
Bởi vì đôi khi bạn có thể bỏ qua dấu ngoặc đơn, đôi khi một tuple cần thêm dấu ngoặc đơn như trong ((1, 2))
và đôi khi dấu ngoặc đơn bên ngoài có thể được bỏ qua, như trong (1, 2)
. Điều này có thể gây nhầm lẫn.
Chức năng / một phần Chức năng chữ với case
Scala có một cú pháp cho chức năng và một phần chức năng chữ. Nó trông như thế này:
{
case pattern if guard => statements
case pattern => statements
}
Những nơi khác mà bạn có thể sử dụng case
câu lệnh là với match
và catch
từ khóa:
object match {
case pattern if guard => statements
case pattern => statements
}
try {
block
} catch {
case pattern if guard => statements
case pattern => statements
} finally {
block
}
Bạn không thể sử dụng các case
câu lệnh trong bất kỳ bối cảnh nào khác . Vì vậy, nếu bạn muốn sử dụng case
, bạn cần niềng răng xoăn. Trong trường hợp bạn đang tự hỏi điều gì làm nên sự khác biệt giữa một chức năng và một phần chức năng theo nghĩa đen, câu trả lời là: bối cảnh. Nếu Scala mong đợi một chức năng, một chức năng bạn nhận được. Nếu nó mong đợi một chức năng một phần, bạn có được một phần chức năng. Nếu cả hai được mong đợi, nó sẽ đưa ra một lỗi về sự mơ hồ.
Biểu thức và khối
Dấu ngoặc đơn có thể được sử dụng để tạo ra các biểu thức con. Niềng răng xoăn có thể được sử dụng để tạo các khối mã (đây không phải là một hàm theo nghĩa đen, vì vậy hãy cẩn thận khi thử sử dụng nó như một). Một khối mã bao gồm nhiều câu lệnh, mỗi câu lệnh có thể là một câu lệnh nhập, một khai báo hoặc một biểu thức. Nó như thế này:
{
import stuff._
statement ; // ; optional at the end of the line
statement ; statement // not optional here
var x = 0 // declaration
while (x < 10) { x += 1 } // stuff
(x % 5) + 1 // expression
}
( expression )
Vì vậy, nếu bạn cần khai báo, nhiều câu lệnh, một import
hoặc bất cứ thứ gì tương tự, bạn cần có dấu ngoặc nhọn. Và bởi vì một biểu thức là một câu lệnh, dấu ngoặc đơn có thể xuất hiện bên trong dấu ngoặc nhọn. Nhưng điều thú vị là các khối mã cũng là các biểu thức, vì vậy bạn có thể sử dụng chúng ở bất cứ đâu trong một biểu thức:
( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
Vì vậy, vì các biểu thức là các câu lệnh và các khối mã là các biểu thức, mọi thứ bên dưới đều hợp lệ:
1 // literal
(1) // expression
{1} // block of code
({1}) // expression with a block of code
{(1)} // block of code with an expression
({(1)}) // you get the drift...
Nơi họ không thể thay thế cho nhau
Về cơ bản, bạn không thể thay thế {}
bằng ()
hoặc ngược lại ở bất kỳ nơi nào khác. Ví dụ:
while (x < 10) { x += 1 }
Đây không phải là một cuộc gọi phương thức, vì vậy bạn không thể viết nó theo bất kỳ cách nào khác. Chà, bạn có thể đặt dấu ngoặc nhọn bên trong dấu ngoặc đơn cho condition
, cũng như sử dụng dấu ngoặc đơn bên trong dấu ngoặc nhọn cho khối mã:
while ({x < 10}) { (x += 1) }
Vì vậy, tôi hy vọng điều này sẽ giúp.