2012-02-10 47 views
7

Tôi đang cố gắng tìm ra cách tạo phương thức nhận đối tượng lồng nhau làm đối số. Đối với một lớp lồng nhau tôi có thể làm như sau:Loại đối tượng lồng nhau trong scala

scala> class Outer { 
| class Inner 
| def method(i:Outer#Inner) = { "inner class" } 
| } 
defined class Outer 

Tuy nhiên, nếu tôi cố gắng một cái gì đó như thế với một đối tượng thay vì tôi nhận được một lỗi:

scala> class Outer { 
| object Inner 
| def method(i:Outer#Inner) = { "inner object" } 
| } 
<console>:11: error: type Inner is not a member of Outer 
    def method(i:Outer#Inner) = { "inner object" } 

gì nên loại đối số đến phương pháp để thực hiện điều này? Ngoài ra tôi muốn tham khảo loại đối tượng Inner không khái quát đối số để nói Any.

Trả lời

12

Inner là một đối tượng, do đó, đó không phải là loại và không thể sử dụng làm loại. loại InnerInner.type. Nó có nghĩa là, trong ví dụ của bạn. Thật không may, mỗi trường hợp của Outer sẽ có đối tượng Inner riêng của nó và loại Outer#Inner.type không thể được sử dụng, vì nó không ổn định. Giải pháp thay thế là sử dụng: this.Inner.type.

def method(i:this.Inner.type) = { "inner object" } 

Nhưng điều đó có nghĩa là bạn chỉ có thể chuyển làm tham số đối tượng Nội bộ của cá thể mà bạn gọi method.

+0

này không biên dịch. –

+1

Oups, bạn cũng nên sử dụng nó, thay vì Outer. Tôi phải đọc lại lời giải thích về kiểu phụ thuộc để giải thích nó. – Nicolas

+0

Có công trình này! Ngoài ra để sử dụng Inner trong một phương thức được định nghĩa bên ngoài lớp bên ngoài, tôi có thể định nghĩa trong Outer: 'type InnerType = this.Inner.type' Và sau đó tôi có thể định nghĩa một phương thức như:' def method (i: Outer # InnerType) = "foo" ' –

7

Một ví dụ đơn giản để minh họa cho những gì đang xảy ra ở đây (trong REPL):

object A 
def foo(a : A) = "Does not compile" 
def bar(a : A.type) = "Does compile!" 
bar(A) // returns "Does compile!" 

Như Nicholas nói, Nội không phải là một loại, vì vậy bạn không thể sử dụng nó như vậy.

Cố gắng hiểu động lực của bạn, tôi đã đưa ra một cái gì đó như thế này:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Inner.type) = x.getI 
} 

Đây là một chút vô nghĩa, vì chúng ta sẽ chỉ trực tiếp tham khảo Nội - sau khi tất cả, chỉ có một trong số đó:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo = Inner.getI 
} 

Tôi đoán rằng những gì bạn muốn làm là chấp nhận Nội trong từ bất kỳ trường hợp nào của Bên ngoài. Chúng tôi có thể kiểm tra loại một điều như vậy:

val o = new Outer(1) 
:type o.Inner 
o.Inner.type 

Vì vậy, chúng ta có thể mong đợi để có thể làm điều gì đó như thế này:

class Outer(i : Int) { 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Outer#Inner.type) = x.getI 
} 

này, tuy nhiên, thất bại trong việc biên dịch. Tôi cung không chăc tại sao. Gõ bí danh để giải cứu!

class Outer(i : Int) { 
    type Inner = Inner.type 
    object Inner { 
    def getI : Int = i 
    } 
    def foo(x : Outer#Inner) = x.getI 
} 

val a = new Outer(1) 
val b = new Outer(2) 
a.foo(b.Inner) //returns 2 

Tôi đoán đó chỉ là hạn chế của trình phân tích cú pháp mà không thể đọc nội dung nào đó ở dạng A#B.type. Bạn có khả năng gửi yêu cầu lỗi.

+0

Là 'loại Inner = Inner.type' giống như' loại Inner = this.Inner.type'? hoặc hai người đó có đề cập đến hai loại khác nhau không? –

+1

Đúng, chúng đề cập đến cùng một điều. – Submonoid

0

Mỗi Scala object có loại riêng và có chính xác một giá trị thuộc loại đó - chính đối tượng đó. Do đó, loại Scala object không hữu ích hơn loại Unit.

Ví dụ, nói rằng bạn có một object A và tuyên bố một phương pháp hay chức năng mà phải mất một A.type tham số:

def foo(arg: A.type) = {} 

Kể từ sẽ luôn tồn tại đúng một giá trị của loại A.type, chúng ta mất đi không có tính tổng quát bằng cách thay vì tham khảo nó trực tiếp bên trong phương thức foo.

Nếu bạn thấy mình muốn làm điều này, đó là nhiều khả năng rằng những gì bạn thực sự muốn trừu tượng hơn là một đặc điểm hoặc cơ sở lớp của đối tượng:

trait Useful { def usefulness: Int } 
object A extends Useful { override val usefulness = 42 } 
class Foo { 
    def foo(arg: Useful) = arg.usefulness 
} 
Các vấn đề liên quan