0

わかりました、それで、私は以前にこれについて尋ねました。理想的には、型を一貫して指定する方法を理解するのに役立つ一般的な答えを探していますが、その代わりに、特定の問題を解決する方法に落ち着きます。これまでのところ、各ソリューションにはさらに 3 つの問題があるようです。アプリケーション全体をここに置くことは避けようとしていますが、私の目標は、再帰的にパラメーター化された特性タイプのタイプをどこからでも便利な方法で参照する方法を見つけることです。その特性タイプの値を交換可能に使用できる自明でないプログラム。

したがって、ここにさらにサンプルコードがあります:

//trait file, shouldn't need to know about implementing class.
trait MyTrait[T <: MyTrait[T]] { self:T =>
  val listOfT: List[T]
  def getFirst:T
  def getOne:T = if( !listOfT.isEmpty ) getFirst else self
}

case class Foo[A <: MyTrait[A]](i: MyTrait[A])

object MyTrait {
  def doSomething
      [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (t: U[T]): T = t.getFirst

  def testMethod1
      [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (something:Foo[T]):T=
              //error! type mismatch.  found:T, required: ?U[?T]
              doSomething(something.i.getOne)

  def testMethod2
       [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (something:Foo[T]):T=
        //error! type mismatch.  
        // found: something.i.type (with underlying type this.MyTrait[T]
        //required: T
        something.i

  def testMethod3
       [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (something:Foo[U[T]]):U[T]=
        //error: type arguments [U[T]] do not conform to class 
        //Foo's type parameter bounds [A <: this.MyTrait[A]]
        something.i.getOne


  // this works! ...but aren't something.i.getOne and something.i the same type?
  // why does testMethod2 fail if this works ?
  // what if I want to have a method that might return something.i and might return
  // soemthing.i.getOne?  What would the interface for that look like?
  def testMethod4
       [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (something:Foo[T]):T=
        something.i.getOne

  def testMethod5
       [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]]
      (something:Foo[U[T]]):U[T]=
        //error: type mismatch;
        //found: something.i.type (with underlying type this.MyTrait[U[T]]
        // required: U[T]
        something.i


}

//class file, shouldn't need to have MyTrait anywhere except 'extends' line.
//should be a usefull class on its own without adding the trait.
class MyClass extends MyTrait[MyClass] {
  //the point of using the parameterized type is to be able to return of 
  //List[MyClass] here instead of List[MyTrait] without having to override
  // some 'type' attribute in anything that uses the trait.
  override val listOfT: List[MyClass] = List[MyClass](this)
  override def getFirst: MyClass = listOfT.head
}


//some client code:
val mc = new MyClass
val foo = Foo(mc)
MyTrait.doSomething(foo.i)
//MyTrait.testMethod1(foo)

型パラメーターの使用方法を理解しました: [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]] この質問への回答から: ケースクラスフィールドの再帰型パラメーター

私は基本的に同じことをもう一度尋ねていますが、問題をもう少し進めています。ここで、something.i は基本的に something.i.getOne と同じ型を持っていることがわかりますが、これらの型は同じ意味で使用することはできません。そのため、オブジェクトをさまざまな関数のパラメーターとして一貫して使用することはできません。something.i と something.i.getOne (実際にはおそらく同じオブジェクト) がコンパイラと型システムによって認識されるのと同じ型を持つように、このコードを機能させるにはどうすればよいでしょうか?

この特定の質問の要点は、サンプル コードの testMethod4 にあります。

4

1 に答える 1

1

このパターンは、このトレイトを拡張し、メソッド全体でそれ自体のインスタンスを返すことを保証するため、 ではなく でMyTrait[A <: MyTrait[A]]直接作業する必要があることを意味します。AMyTraitA

したがって、間違いは の定義ですFoo。単純に次のようにする必要があります。

case class Foo[A <: MyTrait[A]](i: A)

の指定された修正によりFooMyClassコンパイルと「クライアント コード」も修正されます。


さらに、型 like をネストしU[X <: MyTrait[X]] <: MyTrait[X]]ても意味がありません。最終的には、表現タイプが1 つになります。メソッドの引数は反変の位置にあるため、型の引数があれば完全に十分でありT <: MyTrait[ T ]、どんなに具体的であっても、任意の表現型に固執できます。言い換えれば、Foo[U[T]]以上の利点はありませんがFoo[T]、物事が不必要に複雑になります。すべてのテスト メソッドで、基本的にU型パラメーターを削除できます。

object MyTrait {
  def doSomething[T <: MyTrait[T]](t: T): T = t.getFirst

  def testMethod1[T <: MyTrait[T]](something: Foo[T]): T =
    doSomething(something.i.getOne)

  def testMethod2[T <: MyTrait[T]](something: Foo[T]): T = something.i    
  def testMethod3[T <: MyTrait[T]](something: Foo[T]): T = something.i.getOne
  def testMethod4[T <: MyTrait[T]](something: Foo[T]): T = something.i.getOne
  def testMethod5[T <: MyTrait[T]](something: Foo[T]): T = something.i
}
于 2012-09-09T10:00:41.293 に答える