2011-07-12 72 views
6

美好的一天! 我是很新的階,所以在開發過程中以下問題有人提出:類型參數化或結構子類型或

我想描述類樹[T],其中牛逼是類型參數。 但T應當constrainted - 它應該有2種方法: DEF鍵():一個,其中一個是某種類型,從方法的實現 和高清工會衍生(X:T):T(!),其中T與類型參數相同。 我想這種約束可以通過多種方式來表達:

  1. 定義兩個特點一個與方法關鍵和其他與方法工會(兩個特點是因爲這些方法的獨立性質)使用
  2. 結構性亞型
  3. 別的東西...

所以,我該怎麼辦它每路?並以其他方式存在?

此外它會很好,如果它很容易添加這些方法的簡單類型(如字符串,詮釋等)。

回答

5

您可以爲key定義結構類型,但不適用於union。結構類型可能不涉及自身之外定義的抽象類型。所以這是行不通的:

trait Tree[T <: { def union(x: T): T }] 

你可以定義一個特質是的Tree元素必須可用,但:

trait TreeVal[T] { 
    type A 
    def key: A 
    def union(x: T): T 
} 

這可以採用兩種方法。首先,這些類必須實現該接口,這會嚴重限制哪些類可以用作關鍵字。這將是這樣的:

trait Tree[T <: TreeVal[T]] 

它也可以提供作爲一個隱式轉換,就像這樣:

class IntVal(v: Int) extends TreeVal[Int] { 
    type A = Int 
    def key: A = v 
    def union(x: Int): Int = x + v 
} 
implicit def IntIsVal(v: Int): IntVal = new IntVal(v) 

class Tree[T <% TreeVal[T]] // must be class, so it can receive parameters 

該使用什麼叫做約束一個視圖。仔細查看,瞭解更多信息,但足以說您可以對任何具有已定義的隱式轉換的內容進行處理,並且範圍就好像它是TreeVal。例如:

class Tree[T <% TreeVal[T]](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) { 
    override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), node.key, right.getOrElse("o")) 
} 

或者,你可以用型類模式使用它,有幾個變化:

trait TreeVal[T] { 
    type A 
    def key(v: T): A 
    def union(x: T, y: T): T 
} 
class Tree[T : TreeVal] // must be class, so it can receive parameters 

Type類模式使用的上下文範圍。查看更多信息。這種風格通常比現在的風格更受歡迎,因爲它在很多方面都更加靈活。不過,兩者都會起作用。

在這種情況下,人們會使用這樣的:

implicit object IntVal extends TreeVal[Int] { 
    type A = Int 
    def key(v: Int) = v 
    def union(x: Int, y: Int) = x + y 
} 

class Tree[T: TreeVal](node: T, left: Option[Tree[T]], right: Option[Tree[T]]) { 
    val treeVal = implicitly[TreeVal[T]] 
    import treeVal._ 

    override def toString = "(%s < %s > %s)" format (left.getOrElse("o"), key(node), right.getOrElse("o")) 
} 
+0

優秀的解釋,非常感謝! – newf

+0

但是還有一個問題:爲什麼我應該在'implicit object IntVal'中顯式指定'type A'?它可以從'def key'定義中推斷出來嗎? – newf

+0

也許你可以使用'key'方法的參數化版本:'def key [A]:A' – incrop

2

結構類型使用Java反射來實現,所以它們會降低性能。對於類似腳本的短程序或初始化來說沒關係,但任何密集的使用都可能會使程序癱瘓......

所以我會選擇你的第一個選項。您至少需要兩個類型參數。但是,你可以只用一個特質去,如果你並不需要更細的粒度:

trait Tree[T,A] { 
    def key(): A 
    def union(x: T): T 
} 
+0

這聽起來像他想上'T'而不是'Tree'定義的方法。 –

3

如果你希望能夠「增加」,這些方法簡單類型,也許你會更好用類型類。 Read more about type classes in this question,並查看凱文賴特的答案,該答案顯示如何將zeroappend方法「添加」到IntString