2011-01-07 67 views
15

我有一個抽象類:Scala的泛型方法重寫

abstract class Foo(...){ 
    def bar1(f : Foo) : Boolean 
    def bar2(f : Foo) : Foo 
} 

多類擴展Foo和覆蓋的方法

class FooImpl(...) extends Foo{ 
    override def bar1(f : Foo) : Boolean { 
     ... 
    } 
    override def bar2(f : Foo) : Foo { 
     ... 
    } 
} 

是否有可能,使用泛型(或東西),使覆蓋方法有實現它的子類的參數類型?就像這樣:

class FooImpl(...) extends Foo{ 
    override def bar1(f : FooImpl) : Boolean { 
     ... 
    } 
    override def bar2(f : FooImpl) : FooImpl { 
     ... 
    } 
} 

我在想沿着以下線的東西,但似乎並沒有工作...

abstract class Foo(...){ 
    def bar1[T <: Foo](f : T) : Boolean 
    def bar2[T <: Foo](f : T) : T 
} 

class FooImpl(...) extends Foo{ 
    override def bar1[FooImpl](f : FooImpl) : Boolean { 
     ... 
    } 
    override def bar2[FooImpl](f : FooImpl) : FooImpl{ 
     ... 
    } 
} 

任何幫助,非常感謝!

謝謝。

回答

17
abstract class Foo{ 
    type T <: Foo 
    def bar1(f:T):Boolean 
    def bar2(f:T):T 
} 

class FooImpl extends Foo{ 
    type T = FooImpl 
    override def bar1(f:FooImpl) = true 
    override def bar2(f:FooImpl) = f 
} 

在這個版本中的Foo所有份額Foo作爲超不同的子類,但持有的bar2在設定的返回值(或參數bar1bar2),所有你知道你的對象(假設它被命名爲obj)是它是Foo,您需要使用類型obj.T作爲變量的類型。

+0

這使人們有可能是我的本意去做。因此,通過使用「type T <:Foo」,我創建了一個類型T,它既可以是Foo也可以是其任何子類,然後我可以在類中像任何其他類型那樣使用該類型,無論我想要什麼。無論是作爲參數,var類型,返回值,...正確?非常感謝你。在旁註中;我對這篇文章的反應速度感到驚喜。帽子關閉:-) – 2011-01-07 17:26:19

+0

你是對的。 – 2011-01-07 17:42:22

2

T需要是您繼承的Foo類的類型參數,而不是方法本身。

abstract class Foo[T <: Foo[T]]{ 
    def bar1(f:T):Boolean 
    def bar2(f:T):T 
} 

class FooImpl extends Foo[FooImpl]{ 
    override def bar1(f:FooImpl) = true 
    override def bar2(f:FooImpl) = f 
} 

Foo不同的子類實際上並沒有在這個版本的代碼的通用超,因爲他們從Foo不同的參數擴展。當你需要使用公共超類型時,你可以使用引用Foo[T]的參數化方法,但我傾向於選擇我在其他答案中發佈的抽象類型解決方案,因爲它不會將泛型的細節泄露給所有的其他功能必須處理Foos。

0

可以參數Foo來完成一些效果容易:

abstract class Foo[F <: Foo[F]] { def f: F } 
class Food extends Foo[Food] { def f = this } // Yay! 
class Fool extends Foo[Food] { def f = new Food } // Uh-oh... 

如果你想排除第二種情況下,有一個與Scala的當前功能做到這一點沒有直接的方法。

另外,如果您在Foo中給出實際實現,那麼您似乎想要的某些內容沒有意義。如果Foo承諾採取任何Foo,但您給它一種只堅持Food的方法,如果您通過Foo的不同子類(例如Fool),它將會中斷。所以編譯器不會讓你這樣做。

abstract class Foo { def bar(f: Foo) : Foo } 
class Foot extends Foo { def bar(f: Foo) = this } // Fine! 
class Fool extends Foo { def bar(f: Fool) = this } // No good! 
12

爲了讓肯Blum的第二個版本一點點更好,你可以使用自己的類型:

abstract class Foo[T] { self:T => 
    def bar1(f:T):Boolean 
    def bar2(f:T):T 
} 

class FooImpl extends Foo[FooImpl]{ 
    override def bar1(f:FooImpl) = true 
    override def bar2(f:FooImpl) = f 
} 
1

理想的情況下你把上面提到的東西,即

trait Foo[T <: Foo[T]] { self:T => 

「[T <:富[T]]」 表示T是符[T], 的子類, 「自:T =>」 是指富[T]是T的子類,並且一起這是一個有點古怪的方式告訴大家,富[T]是完全一樣的T.

只有那些打算我可以做下面的代碼編譯和工作:

trait Field[T <: Field[T]] { self:T => 

    def x2:T 

    def +(that:T):T 

    def *(n:BigInt) : T = { 
    if(n == 1) 
     this 
    else if(n == 2) 
     this.x2 
    else if(n == 3) 
     this + this.x2 
    else { 
     val p = (this * (n/2)).x2 
     if (n%2==0) 
     p 
     else 
     p + this 
    }   
    } 

}