2012-12-14 33 views
12

Tôi luôn tự hỏi tại sao đôi khi với các hàm chức năng, chúng ta có thể bỏ qua dấu ngoặc nhọn ngay cả đối với nhiều câu lệnh. Để minh họa điều này, cú pháp của hàm multiline là để kèm theo các câu lệnh với các dấu ngoặc nhọn. Giống như vậy,Đa nguyên hàm theo nghĩa đen trong Scala

val fl = (x: Int) => { 
    println("Add 25 to "+x) 
    x + 25 
} 

Tuy nhiên, khi bạn chuyển sang hàm đơn đối số, bạn có thể bỏ qua dấu ngoặc nhọn bắt buộc cho hàm theo nghĩa đen.

Vì vậy, đối với một chức năng nhất định f,

def f(fl: Int => Int) { 
    println("Result is "+ fl(5)) 
} 

Bạn có thể gọi f() như thế này,

f(x=> { 
    println("Add 25 to "+x) 
    x + 25 
}) 
------------------------- 
Add 25 to 5 
Result: 30 

Hoặc khi bạn sử dụng dấu ngoặc nhọn thay vì ngoặc trong cuộc gọi chức năng, bạn có thể loại bỏ các dấu ngoặc nhọn bên trong khỏi hàm hàm. Vì vậy, mã sau cũng sẽ hoạt động,

f{ x=> 
    println("Add 25 to "+x) 
    x + 25 
} 

Mã trên có thể đọc được và tôi nhận thấy rằng rất nhiều ví dụ sử dụng cú pháp này. Tuy nhiên, có quy tắc đặc biệt nào mà tôi có thể đã bỏ sót hay không, để giải thích tại sao điều này hoạt động như dự định?

Trả lời

20

Chỉ có một vài quy tắc cú pháp đơn giản. Các phụ lục của spec là giá trị perusing.

Hàm chức năng hoặc ẩn danh (6.23) trông giống như x => Expr hoặc x => Block tùy thuộc vào ngữ cảnh tương ứng là Expr hay ResultExpr.

Ứng dụng chức năng (6.6) trông giống như f(Expr, Expr) hoặc f BlockExpr, tức là f{ Block }. Tức là, một BlockExpr chỉ là một chuỗi các câu lệnh chặn bên trong {...}.

Khi bạn gọi f(g), thì g là số Expr, như hàm theo nghĩa đen, x => Expr. Expr có thể là một BlockExpr, x => { ... }.

Khi bạn gọi f{ Block }, sau đó f { x => ... } có chức năng bằng chữ trong ResultExpr của một khối (chỉ là một chuỗi các câu lệnh, không cần dấu ngoặc ôm).

Ở đây, rõ ràng là các func anon là ở dưới cùng của một khối:

scala> def m(x: Int=>Int) = x(5) 
m: (x: Int => Int)Int 

scala> m { 
    | val y = 7 
    | x => // no brace 
    | x+y+1 
    | } 
res0: Int = 13 
+0

Đây là lời giải thích tôi đang tìm kiếm. Ngoài ra, ngoài các phần của thông số bạn đã đánh dấu, bạn cũng có thể tham khảo phần Blocks (6.11) để hiểu rõ hơn. – jafaeldon

+0

Câu trả lời gấc, tôi không thể giải thích rõ hơn. Upvoted nó. Chúc mừng! – wleao

8

Đây là một trong những điều khiến Scala trở nên xinh đẹp với tôi.

Câu trả lời đơn giản cho câu hỏi của bạn là:

Dấu ngoặc đơn() dành cho các công trình đơn lẻ. Ví dụ: hoạt động này:

def f(fl: Int => Int) { 
    println("Result is " + fl(5)) 
    } 

    f(
    x => 
    x + 25) 

    f(x => x + 25) // single line 

và dấu ngoặc nhọn {} có nghĩa là cho câu lệnh nhiều dòng. Ví dụ, công trình này:

f { 
    x => 
    println("Add 25 to " + x) 
    x + 25 
} 

nhưng mã này không hoạt động:

f ( 
    x => 
    println("Add 25 to " + x) 
    x + 25 
) 

Trình biên dịch phàn nàn với thông báo sau:

giá trị x không phải là một thành viên của Đơn vị nguyên nhân có thể: có thể dấu chấm phẩy là bị thiếu trước `giá trị x '?

Nếu bạn thêm dấu chấm phẩy, bạn sẽ gặp lỗi cú pháp do dấu ngoặc đơn chưa khớp.

Nếu bạn cố gắng làm điều này:

f { x => println("Add 25 to " + x) x + 25 } 

Trình biên dịch sẽ lấy lại cho bạn với thông điệp:

value x is not a member of unit 

Bạn nhận được rằng ông đang cố gắng tìm x như là một thành viên của đơn vị. Giống như:

f { println("Add 25 to " + x).x.+(25) } 

Điều rõ ràng là sai.

Nếu bạn thêm dấu ngoặc nhọn bên trong, Như thế này:

f ( 
    x => { 
    println("Add 25 to " + x) 
    x + 25 
    } 
) 

này cũng sẽ làm việc, nhưng bạn vẫn còn có một tuyên bố multiline đó được đánh dấu bằng việc sử dụng các dấu ngoặc nhọn. Vì vậy, trình biên dịch biết những gì bạn muốn có để in đầu tiên và sau đó thêm 25 đến x.

Tôi đã bị những người tinh tế cắn trước đó. Kể từ đó, tôi đã chú ý đến cách tôi mã với những người, bởi vì bạn sẽ mã và đọc rất nhiều điều này khi bạn chủ yếu sử dụng bản đồ, flatMaps, foreachs, fors và currying.

Chúc mừng!

Các vấn đề liên quan