2012-04-30 33 views
6

Tôi đã theo ấn tượng rằng đâychức năng cà ri Overriding trong Scala

// short syntax 
def foo(bar: Bar)(baz: Baz): Quux 

là đường cú pháp cho việc này

// long syntax 
def foo(bar: Bar): (Baz) => Quux 

Nhưng tôi dường như không thể kết hợp cả hai khi nói đến thừa kế. Toàn bộ cây phải được xác định bằng cú pháp ngắn hoặc cú pháp dài; không bao giờ cả hai.

Ví dụ:

case class Context 
case class Work 

trait ContextualWorker { 
    def workWithContext(ctxt: Context)(work: Work): Traversable[Work] 
} 

class ShortConcreteWorker extends ContextualWorker { 
    override def workWithContext(ctxt: Context)(work: Work) = Nil 
} 

class LongConcreteWorker extends ContextualWorker { 
    // error on next line: method workWithContext overrides nothing <------------- 
override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = { 
    val setupCode = 1 
    { work => Nil } 
    } 
} 

Nếu tôi thay đổi đặc điểm để sử dụng cú pháp dài, sau đó ShortConcreteWorker không biên dịch.

Có lý do nào khiến chúng không thể thay đổi/kế thừa được không? Làm thế nào bạn có được xung quanh nó?

Ngay bây giờ các cách tiếp cận linh hoạt nhất dường như là để xác định cây trong cú pháp dài, có lẽ ủy thác cho một lớp học thực hiện trong ShortConcreteWorker như vậy:

case class Context 
case class Work 

trait ContextualWorker { 
    def workWithContext(ctxt: Context): (Work) => Traversable[Work] 
} 

class ShortConcreteWorker extends ContextualWorker { 
    override def workWithContext(ctxt: Context) = workWithContextImpl(ctxt)_ 
    private def workWithContextImpl(ctxt: Context)(work: Work) = Nil 
} 

class LongConcreteWorker extends ContextualWorker { 
    override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = { 
    val setupCode = 1 
    { work => Nil } 
    } 
} 
+0

Tôi đoán bạn đang dựa trên giả định của bạn trên [trang này trên trang Scala] (http://www.scala-lang.org/node/135). Thật không may là nó không hoàn toàn chính xác, xem phần 3.3.1 của thông số kỹ thuật Scala. – rxg

Trả lời

5

Hai phương pháp được mô tả khá đơn giản có chữ ký khác nhau . REPL xác nhận điều này:

scala> def foo1(a: Int)(b: Int): Int = a + b 
foo1: (a: Int)(b: Int)Int 

scala> def foo2(a: Int): (Int => Int) = (b: Int) => a + b 
foo2: (a: Int)Int => Int 

Đầu tiên là hàm yêu cầu hai đối số, được đưa ra trong danh sách đối số riêng biệt và trả về Int. Thứ hai là hàm nhận số đối số một đối số và trả về hàm từ Int đến Int. Trong khi hai điều này là khái niệm tương tự nhau, chúng thực ra là các cấu trúc khác nhau, và Scala đối xử với chúng như vậy.

Điều này không giới hạn đối với các hàm có nhiều danh sách đối số. Nó hoạt động theo cách tương tự tại đây:

scala> def foo3(a: Int): Int = a + 1 
foo3: (a: Int)Int 

scala> def foo4: (Int => Int) = (a: Int) => a + 1 
foo4: Int => Int 

Lưu ý rằng cũng có các nhánh khác nhau để sử dụng. Với foo2, bởi vì nó chỉ chấp nhận một đối số, chúng ta có thể gọi nó chỉ với một đối số. Tuy nhiên, foo1 yêu cầu hai đối số, vì vậy chúng tôi không thể chỉ đơn giản gọi nó bằng một đối số. Tuy nhiên, bạn có thể sử dụng cú pháp _ để chuyển đổi nó thành một hàm có thể gọi.

foo2(2) // Int => Int = <function1> 
foo1(2) // error: missing arguments for method foo1 
foo1(2) _ // Int => Int = <function1> 

Vì vậy, để trả lời câu hỏi của bạn trực tiếp: Lý do chúng không thể thay thế được vì chúng không giống nhau. Nếu chúng giống nhau, chúng ta có thể gọi chúng theo cùng một cách. Nếu bạn có thể thay đổi chữ ký sau khi mở rộng, làm thế nào Scala sẽ biết cú pháp gọi cho phép? Cách để "đi lại" điều này đơn giản là làm cho chữ ký nhất quán.

+0

Có thể hữu ích khi thêm rằng nếu chúng ta có, ví dụ 'def g (f: Int => Int)' thì chúng ta có thể gọi nó là 'g (foo1 (3))' hoặc 'g (foo2 (3)) '. Vì vậy, trong một số trường hợp, hai kiểu có thể không thể phân biệt được. – rxg

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