2011-07-30 14 views
5

Trong một lớp học Scala, tôi thuận tiện có thể khai báo kiểu trả về của một phương pháp để có this.type để đảm bảo rằng nó sẽ trở về cùng một đối tượng nó được gọi vào lúc:Làm thế nào tôi có thể cung cấp một bảo đảm thời gian biên dịch rằng phương pháp của tôi sẽ trả về cùng một đối tượng mà nó nhận được trong Scala?

class Foo { 
    def bar: this.type = this 
} 

Có cách nào tôi tương tự có thể chỉ định một phương thức chấp nhận thông số AnyRef nhất định sẽ trả về chính xác tham chiếu đó? Đoạn sau đây không cung cấp bảo lãnh này, tôi có thể trở lại bất kỳ trường hợp A:

def processAndReturn[A <: AnyRef](obj: A): A = { 
    // work with obj 
    obj 
} 

Trả lời

8

huitseeker là thực sự có giá trị với -Ydependent-method-types tùy chọn:

$ scala -Ydependent-method-types 
Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_24). 

scala> def processAndReturn[A <: AnyRef](obj: A): obj.type = { 
    |  // work with obj 
    |  obj 
    | } 
processAndReturn: [A <: AnyRef](obj: A)obj.type 

scala> processAndReturn("hi") 
res1: java.lang.String = hi 

Từ this thread, tôi thu thập rằng thử nghiệm loại phương pháp phụ thuộc đã được khoảng một thời gian, và thậm chí có một bài báo công bố việc sử dụng chúng, nhưng việc thực hiện có thể bị lỗi. Đã có một số cuộc thảo luận về làm lại nền tảng hệ thống kiểu Scala (xem Adriaan Moor's slides về các loại đối tượng phụ thuộc). Nếu nó hoạt động, tôi tưởng tượng rằng các kiểu phương thức phụ thuộc (trong số những thứ khác) sẽ hoàn toàn kosher trong các phiên bản tương lai của Scala.

0

Câu hỏi đặt ra là: nếu bạn đang đi để trả lại những gì bạn đã nhập, tại sao không chỉ sử dụng khoảng trống? Sau khi tất cả, bạn đã có đối tượng trong mã gọi, phải không?

+1

có lẽ, nhưng đó không phải là thực sự là điểm; Tôi quan tâm đến hệ thống kiểu và thời gian biên dịch đảm bảo nó có thể hoặc không thể cung cấp. 'này.loại' ví dụ là rất thuận tiện cho các cuộc gọi phương thức chuỗi trên cùng một đối tượng. –

3

Tôi đoán bạn muốn cung cấp loại trả lại obj.type theo phương pháp của bạn ở trên, nhưng điều này không may bị cấm kể từ bây giờ. Theo the spec, p.47:

(...) tại các loại thông số phương pháp singleton hiện tại chỉ có thể xuất hiện trong phương thức thân; các kiểu phương thức phụ thuộc không được hỗ trợ.

Có thể có một số cách để đạt được những gì bạn muốn, nhưng không phải trong đặc tả loại của chính phương thức đó. đề nghị

1

huitseeker và Kipton có thể có câu trả lời trực tiếp mà bạn đang tìm kiếm.

Với điều đó đã nói, trường hợp sử dụng duy nhất tôi có thể tưởng tượng là nếu bạn muốn chuỗi cuộc gọi trên cùng một đối tượng và đảm bảo bạn đang thực sự làm việc trên cùng một đối tượng. Có cái nào khác không?

Ví dụ:

class Counter { 
    var i = 0 
    override def toString = i.toString 
} 

def incr(c: Counter): Counter = { c.i += 1; c } 

val two = incr(incr((new Counter))) 
// two: Counter = 2 

Nếu tôi gọi incr hai lần liên tiếp, tôi hy vọng sẽ nhận được hai. Bây giờ hãy tưởng tượng tôi đang làm việc với một chức năng bệnh cư xử như:

def incorrect_incr(c: Counter): Counter = { 
    c.i += 1 
    new Counter // should return c but does not 
} 

val notTwo = incorrect_incr(incorrect_incr(new Counter)) 
// notTwo: Counter = 0 

Tôi nghĩ rằng sử dụng một wrapper để đảm bảo chúng tôi tiếp tục làm việc trên cùng một đối tượng sẽ giải quyết vấn đề này (thay đổi nội dung sau khi suy nghĩ về cách làm này nhiều thành ngữ):

case class Id[T <: AnyRef](t:T) { 
    def map[U](f: (T) => U): Id[T] = { 
    f(t) 
    this 
    } 
    def get: T = t 
} 

val reallyTwo = Id(new Counter).map(incorrect_incr).map(incorrect_incr).get 
// reallyTwo: Counter = 2 

map về cơ bản đảm bảo các chức năng được gọi là cho tác dụng phụ của nó, get unwraps giá trị ...

+0

Một trường hợp sử dụng hợp lệ khác mà tôi có thể tưởng tượng là mô phỏng phương thức trả về 'this.type' bằng mẫu pimp-my-library. –