2013-10-08 36 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),所以这很好。

相关问题