2011-02-07 29 views
7

Given:ứng dụng chức năng phần sớm chạy codeblock khi được sử dụng với gạch

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

tôi có thể gọi nó với:

save("test")(true) -> running f 
save("test")(false) -> not running f 
save(throw new RuntimeException("boom!"))(false) -> not running f 
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown 

Đây là hành vi tò mò với ứng dụng phần:

save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected 
save(throw new RuntimeException("boom!")) _ -> exception thrown 

Khóa mã được đánh giá ngay lập tức mà không được chuyển thành một hàm. Sự khác nhau giữa 2 câu trên là gì?

+1

Bạn có thể tìm thấy một số giải thích tại đây: http://stackoverflow.com/questions/2363013/in-scala-why-cant-i-partially-apply-a-function-without-explicitly-specifying-it –

+3

IMHO, đây là một lỗi. –

Trả lời

2

Trường hợp đầu tiên,

save(throw new RuntimeException("boom!")) _ 

Theo "Scala Reference" (§6.7), trailing gạch được sử dụng ở vị trí của danh sách đối số, và biểu hiện được chuyển đổi sang

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!")) 

nơi đầu tiên đối số của def save được đánh giá ngay lập tức.

Biểu thức e _ được tạo đúng nếu e là loại phương thức hoặc nếu e là tham số từng tên một . Nếu e là phương pháp có tham số, e _ đại diện cho e được chuyển đổi thành loại hàm theo eta mở rộng (§6.26.5). Nếu e là một tham số không có tham số hoặc tên tham số của loại => T, e _ đại diện cho chức năng loại() => T, trong đó đánh giá e khi nó được áp dụng cho rỗng danh sách tham số() .

Để thực hiện những công việc như bạn mong đợi, một số sửa đổi được yêu cầu:

scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") } 
save: (f:() => Any)(run: Boolean)Unit 

scala> val f = save(() => throw new RuntimeException("boom!")) _ 
f: (Boolean) => Unit = <function1> 

scala> f(true) 
running f 
java.lang.RuntimeException: boom! 
     at $anonfun$1.apply(<console>:6) 

trường hợp thứ hai,

save(throw new RuntimeException("boom!"))(_) 

Theo "Scala Reference" (§6.23), khi giữ chỗ là được sử dụng làm thay thế cho một đối số, biểu thức được chuyển đổi thành

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_) 
+1

Thực sự, theo thông số kỹ thuật được trích dẫn, tôi mong muốn gọi bằng tên để hoạt động. Sau khi tất cả, trong trường hợp đó 'e' chỉ được đánh giá khi được áp dụng cho danh sách tham số trống. –

+0

Tôi đồng ý với Daniel. Nếu như spec cho biết cuộc gọi được chuyển thành() => T thì hàm sẽ không được đánh giá cho đến khi nó được áp dụng. – ssanj

0

Hành vi của các tham số gọi theo tên dưới sự mở rộng eta hiện đang được xem xét, xem this bug. Mã của bạn hoạt động như bạn mong đợi (có nghĩa là, dòng save(throw new RuntimeException("boom!")) _ trả về một hàm mà không cần ném ngoại lệ) với các bản dựng hàng đêm gần đây là 2,10. Hãy xem liệu nó có ở lại cho đến khi phát hành không!

Xem thêm this question cho câu hỏi có liên quan về trường hợp chung về mở rộng eta không liên quan đến từng tên.

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