2013-10-08 43 views
1

我有一個用例,我想這樣做如何檢查方法參數與此方法具有相同的類型?

trait Foo { 
    def bar[T](x: T)(implicit ev: x.type =:= this.type) = {} 
} 

是這樣,一個電話吧只編譯,當參數x具有相同的類型,其中方法被要求的類。

這是明確的,即this.type不會在這種情況下幫助,因爲每個實例有一個不同的this.type,這應該只是說明的目的。

完整的問題是這樣的:

trait Foo { 
    def bar[B <: Foo](o: B) = {} // with some check added 
} 

abstract class Abstract extends Foo 

class Concrete1 extends Abstract 

class Concrete2 extends Abstract 

case class Wrapped(a: Abstract) 

val c1a = new Concrete1 
val c1b = new Concrete1 
val c2 = new Concrete2 
val ts1 = new Wrapped(new Concrete1) 

c1a.bar(c1b) // should compile 
ts1.a.bar(c1b) // should also compile 
c2.bar(c1b) // should not compile 

使用抽象類型我發現,編譯c1a.bar(C1B),並不會編譯c2.bar(C1B)如預期的解決方案,也沒有按編譯ts1.a.bar(c1b)。我還檢查了其他的想法就像在this post UPDATE2描述的方法,但在這裏自我的協方差不允許定義吧。

存在那裏,我沒有看到一個解決方案嗎?沒有使抽象成爲泛型(我想避免)。

感謝

+0

在你的例子中'ts1'的類型是'Wrapped',它與'Abstract'無關。它只是碰巧有一個類型爲「Abstract」的字段,但它的層次結構中沒有任何部分,甚至沒有'bar'方法。 – Chirlo

+0

是的,對不起,這是一個錯誤。當然,我的意思是ts1.a.bar,而不是ts1.bar。 – Klinke

回答

2

做這樣的事情(沒有引入類型的參數)的唯一方法是通過引入abstract typeFoo需要知道的類型,在它的bar方法:

trait Foo { 
    type Self 
    def bar[T <: Self](o: T) = {} // with some check added 
} 

abstract class Abstract extends Foo { 
    type Self = Abstract 
} 

class Concrete1 extends Abstract { 
    type Self = Concrete1 
} 

class Concrete2 extends Abstract { 
    type Self = Concrete2 
} 

這裏的問題是,你可以很容易地在Self類型類型0。這可以通過添加一個名爲StrictSelf新特性來解決(由this question啓發):然後

trait StrictSelf[T <: StrictSelf[T]] { self: T => 
    type Self >: self.type <: T 
} 

完整的代碼應該是這樣的:

trait Foo { self:StrictSelf[_] => 
    def bar[T <: Self](o: T) = {} 
} 

abstract class Abstract extends Foo { self:StrictSelf[_] => } 

class Concrete1 extends Abstract with StrictSelf[Concrete1] { 
    type Self = Concrete1 
} 

class Concrete2 extends Abstract with StrictSelf[Concrete2] { 
    type Self = Concrete2 
} 

case class Wrapped[T <: Abstract with StrictSelf[T]](a: T) 

你的情況,你也可以使用以下(更簡單)的變體:

trait SelfType[T <: SelfType[T]] { self:T => 
    type Self >: T 
} 

trait Foo { self:SelfType[_] => 
    def bar(o: Self) = {} 
} 

abstract class Abstract extends Foo {self: SelfType[_] => } 

class Concrete1 extends Abstract with SelfType[Concrete1] 

class Concrete2 extends Abstract with SelfType[Concrete2] 

case class Wrapped[T <: Abstract](a: T) 
1

你可以參數化的特點是這樣的:

trait Foo[T]{ 
    def bar(t:T) = {} 
} 

,然後擴展特性類將給出自己的類型擴展時:

abstract class Abstract[T] extends Foo[T] 

class Concrete1 extends Abstract[Concrete1] 
class Concrete2 extends Abstract[Concrete2] 
case class Wrapped[T](a:Abstract[T]) 

這將解決你的問題代價是必須定義從Foo延伸的每個類別的類型。

+0

是的,這是真的,但我想避免這種解決方案(我試圖用「沒有使抽象成爲泛型」部分來表達)。正如已經看到的那樣,這也需要一個改變的Wrapper,它只是一個類的抽象類的例子中的佔位符。這只是開始如何傳播到代碼中。 – Klinke

0

EECOLORs答案的偉大工程,是更接近問題,則替代解決方案,我發現自己在其間。但這種替代的解決方案非常適合我的用例,所以也許這可能是也interessting爲別人誰是對這個問題以後stumpling。

我搬到酒吧到一個新的對象:

object Bar { 
    def bar[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: A =:= B) = {} 
} 

也取得包裝類通用:

case class Wrapped[T <: Abstract](a: T) 

當然,你必須寫的,現在Bar.bar(c1a, c1b)代替c1a.bar(c1b)。在我的用例Bar.bar轉換爲Distance.euclidean(c1a, c1b),所以這很好。

相關問題