2012-02-08 12 views
8

Tôi đang cố gắng để quấn đầu của tôi xung quanh trừu tượng và rõ ràng loại tự trong scala. Hãy xem xét ví dụ sau: Tôi muốn tạo ra một cơ sở cho cây mở rộng đơn giản như này:Scala tự loại và this.type trong bộ sưu tập vấn đề

trait Tree { 
    def children: Iterable[Tree] 
    def descendants: Iterable[Tree] = { val dv = children.view; dv ++ (dv.flatMap { _.children }) } 
} 

Tuy nhiên, tôi muốn để có thể mở rộng các nút cây với một số phương pháp và sử dụng các phương pháp như: tree.children foreach { _.newMethod() }

Đối với điều này tôi đã cố gắng:

A. this.type: FAIL

trait Tree { 
    def children: Iterable[this.type] 
    def descendants: Iterable[this.type] = { 
     val dv = children.view 
     // FAIL: type mismatch; found : scala.collection.IterableView[com.abovobo.data.Tree,Iterable[_]] required: Iterable[Tree.this.type] 
     // dv ++ (dv.flatMap { _.children }) 
     // OK: 
     dv.++[this.type, Iterable[this.type]](dv.flatMap[this.type, Iterable[this.type]]{ _.children }) 
    } 
} 

Làm việc biến một lại khá vụng về.

B. Tóm tắt loại: FAIL

trait Tree { 
    type Node <: Tree 

    def children: Iterable[Node] 
    def descendants: Iterable[Node] = { 
     val dv = children.view 
     // FAIL: type mismatch; found : scala.collection.IterableView[com.abovobo.data.Tree#Node,Iterable[_]] required: Iterable[Tree.this.Node] 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

Không làm việc ở tất cả do đường dẫn cụ thể loại không phù hợp như tôi hiểu.

C. Loại params (generics): OK

trait Tree[+Node <: Tree[Node]] { 

    def children: Iterable[Node] 

    def descendants: Iterable[Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

trình OK, nhưng không quá tốt để duy trì trong các lớp thừa kế.

Bất kỳ ý tưởng nào về cách tạo hai biến thể đầu tiên hoạt động mà không cần tấn mã?

Ngoài ra, với this.type tôi đã gặp sự cố khi triển khai.

trait BiDTree extends Tree { 
    def parent: Option[this.type] 
} 

// how to accept this param? Option[TreeImpl] doesn't work. 
class TreeImpl(val parent: Option[???]) extends BiDTree { 
    // ... 
} 

Cảm ơn!

+3

Ah vâng. Vấn đề "Scala không có MyType" một lần nữa. –

+0

như bạn có thể thấy tôi đã xem xét điều này trong SO và đã thử các biến thể được đề xuất. nó hoạt động tốt cho các cấu trúc khá đơn giản (ví dụ như 'c.incr(). decr()' ví dụ trong bài báo của Martin), nhưng với các bộ sưu tập thì không. – tuxSlayer

+1

vâng. có lý do tại sao sau khi đọc thảo luận của bạn ở đây http://www.scala-lang.org/node/6649, cảm ơn – tuxSlayer

Trả lời

1

Vào cuối tôi đã giải quyết với những gì đã được đề xuất trong cuộc thảo luận này http://www.scala-lang.org/node/6649:

trait Tree[+Node <: Tree[Node]] { 
    this: Node => 

    def children: Iterable[Node] 

    def descendants: Iterable[Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

Tức là biến thể (C) nhưng với loại tự rõ ràng. Điều này tạo cơ hội sử dụng this theo các phương pháp khác (ví dụ: phương pháp find(path: String): Option[Node]).

5

Nếu không thực sự hiểu những gì vấn đề là bạn có với (C), bạn có thể thử một biến thể của (B):

trait Tree { 
    type Node <: Tree 

    def children: Iterable[Tree#Node] 
    def descendants: Iterable[Tree#Node] = { 
     val dv = children.view 
     dv ++ (dv.flatMap { _.children }) 
    } 
} 

nào tránh được vấn đề loại hình cụ thể đường dẫn của bạn. Bằng cách này bạn thực sự cần có một cái nhìn tại http://www.assembla.com/spaces/scala-graph/wiki

+1

Ồ, cảm ơn, đã bỏ lỡ ký hiệu chọn kiểu này. Đối với (C) - tôi sẽ thêm các loại này vào tất cả các lớp con. Điều này không phải là rất thuận tiện. – tuxSlayer