2010-05-05 32 views
28
def foo(x:Int, f:Unit=>Int) = println(f()) 

foo(2, {Unit => 3+4} 

//case1 
def loop:Int = 7 
foo(2, loop) //does not compile 

changing loop to 
//case 2 
def loop():Int = 7 
foo(2, loop) // does not compile 

changing loop to 
//case 3 
def loop(x:Unit): Int = 7 //changing according to Don's Comments 
foo(2,loop) // compiles and works fine 

should'nt case 1 và case 2 cũng hoạt động? tại sao họ không làm việc?Chức năng không có đối số, với đơn vị làm đối số trong scala

định foo như

def foo(x:Int, y:()=>Int) 

sau đó trường hợp 2 công trình nhưng không phải trường hợp 1.

Arent tất cả họ đều phải làm việc, quy định chức năng một trong hai cách.

// tôi cũng nghĩ() => Int in foo là kiểu xấu, y: => Int không hoạt động, bình luận ??

+2

def định nghĩa các phương thức (không phải là lớp đầu tiên), không phải các hàm (mà * là * lớp đầu tiên). Ứng dụng một phần nâng cao các phương thức hoạt động khi bạn cần chúng. –

+1

Bạn có thể vui lòng xây dựng .. Tôi đã không nhận được nó. Bạn có nghĩa là, rằng def của không thể được thông qua xung quanh. tức là "vòng lặp" ở trên không thể được chuyển cho các chức năng khác? – scout

+2

Đúng. Khi chúng ta nói "lớp đầu tiên", chúng ta có nghĩa là cùng một trạng thái giống như bất kỳ giá trị nào khác như một Int, một String hoặc một thể hiện của một số lớp do người dùng định nghĩa. Các phương thức không thể được xử lý theo cách này (chúng chỉ có thể được gọi). Các hàm, mặt khác (là các cá thể của (các lớp con của) Hàm N (N là số đối số)), là các thực thể lớp đầu tiên vì lý do rõ ràng là chúng là các cá thể của một lớp. –

Trả lời

74

Scala phân biệt giữa các yếu tố sau:

  • Chức năng/phương pháp với không có danh sách tham số ("bởi tham số -name" nếu một hàm)
  • Chức năng với một danh sách tham số rỗng
  • Chức năng với một tham số kiểu Unit

Không ai trong số đó là tương đương, mặc dù như là một tiện nghi Scala cho phép bạn để bỏ qua danh sách tham số trống. (Ngẫu nhiên, hai danh sách tham số có sản phẩm nào cũng không giống nhau.)

Vì vậy, mặc dù Unit được viết (), đây là không giống như các tham số của hàm Parens () cho một hàm hoặc phương pháp. Thay vào đó, hãy suy nghĩ của () dưới dạng Tuple0.

Vì vậy, nếu bạn nói f: Unit => Int, những gì bạn có nghĩa là "f mất một tham số, nhưng đó là một tham số thực sự nhàm chán vì nó là Unit, mà phải luôn luôn giống nhau nhàm chán Tuple0 giá trị ()". Những gì bạn đang viết thực sự ngắn cho f: (Unit) => Int.

Nếu bạn nói f:() => Int, thì bạn có nghĩa là "f không có tham số và tạo ra Int".

Nếu bạn nói f: => Int, thì bạn có nghĩa là "trì hoãn việc thực hiện bất kỳ câu lệnh nào tạo ra giá trị Int cho đến khi chúng tôi sử dụng nó trong mã này (và đánh giá lại mỗi lần)". Về mặt chức năng, kết quả là về cơ bản giống như f:() => Int (và nội bộ được chuyển đổi thành cùng một lớp Function0), nhưng nó có cách sử dụng khác nhau, có lẽ để cho phép hình thức đóng gọn hơn (bạn luôn bỏ qua mã => trong mã gọi điện).

+0

Vì vậy, nếu tôi có một hàm def loop() = 7 Nó thực sự không có ý nghĩa đối với tôi để chèn đơn vị, như trong def vòng lặp (x: đơn vị) = 7, nếu tôi muốn vượt qua nó đến một chức năng như foo ở trên. – scout

+2

@Scout: Không có lý do gì để thêm một 'Đơn vị' thừa trong trường hợp đó. Nó rất hữu ích cho sự trừu tượng hóa. Giả sử bạn có hàm thành phần: 'def comp [A, B, C] (f: A => B, g: B => C, a: A) = g (f (a))' và bạn cố gắng vượt qua nó là 'f' không trả về giá trị. Bây giờ bạn sẽ làm gì? Vâng, nó chỉ ra rằng Scala luôn _does_ trả lại một cái gì đó - ít nhất là '()' (giá trị duy nhất có thể có của loại 'Đơn vị'). Vì vậy, bây giờ bạn có thể viết một 'g' mà có một đầu vào của loại' Đơn vị' và sử dụng chức năng thành phần chung ở trên. Nhưng đối với hầu hết các tình huống, chỉ cần sử dụng 'def f() = ...' hoặc 'def f = ...'. –

+1

Cảm ơn bạn đã làm rõ. Tôi đã cố gắng tìm ra cách làm thế nào để thực hiện hành động lười biếng. Lưu ý rằng khoảng trống giữa ':' và '=' trong 'f: => Int' là quan trọng. – Jus12

14

() => Int là Function0 [Int] trong khi Unit => Int là Function1 [Unit, Int]

scala> val function0:() => Int =() => 5 
function0:() => Int = <function0> 

scala> val function1: Unit => Int = u => 5 
function1: (Unit) => Int = <function1> 

scala> function0() 
res0: Int = 5 

scala> function1("anything") 
res1: Int = 5 

scala> function1(100) 
res2: Int = 5 

scala> 

Cũng lưu ý rằng() là một đối tượng của đơn vị

scala> function1(()) 
res11: Int = 5 

scala> function1() 
res12: Int = 5 

scala> function1() 
res13: Int = 5 

scala> val unit =() 
unit: Unit =() 


scala> function1(unit) 
res15: Int = 5 

scala> function1 apply unit 
res16: Int = 5 

scala> 
+0

scala> val function1: Unit => Int = Unit => 5 Lưu ý rằng trong dòng này, "Đơn vị" cuối cùng không phải là định danh loại, nhưng chỉ là tên cho tham số (bạn có thể thay đổi thành "x" ví dụ). –

+0

@Dimitris Andreou: Vâng, bạn nói đúng. – Eastsun

+0

Tôi nhận được lý do tại sao 'function1 (())' và 'function1()' hoạt động, nhưng tôi không hiểu tại sao 'function1()' hoạt động. Tôi hy vọng điều này sẽ tuân theo các quy tắc gọi phương thức điển hình trong Scala, nghĩa là, bạn cần khoảng trống sau tên hàm, hoặc giá trị đơn vị giữa các tham số parens ... – ThaDon

2

Trong trường hợp 1 và 2 ở trên, giá trị trả về của loop hơn loop bản thân là loại kiểm tra cho đối số thứ hai để foo và thất bại: Int = Unit => Int

Thay đổi thành vòng lặp có lỗi đánh máy.

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