1

次のようなことをしたいユースケースがあります

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

そのため、パラメーター x がメソッドが呼び出されるクラスと同じ型を持つ場合にのみ、bar の呼び出しがコンパイルされます。

各インスタンスには異なる 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) もコンパイルしないソリューションを見つけました。この投稿の update2 で説明されているアプローチのような他のアイデアも確認しましたが、ここでは Self の共分散によりバーを定義できません。

私が見ていない解決策はありますか?Abstract をジェネリック型にしない限り (これは避けたい)。

ありがとう

4

3 に答える 3

2

このようなことを (型パラメーターを導入せずに) 行う唯一の方法は、abstract type. メソッドFooの型を知る必要があります。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これは、(この質問StrictSelfに触発された)と呼ばれる新しい特性を追加することで解決できます。

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)
于 2013-10-08T21:59:45.087 に答える
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

于 2013-10-08T18:44:09.963 に答える