好的,所以,我以前问过这个问题。理想情况下,我正在寻找一个通用答案,以帮助我理解如何一致地指定类型,但取而代之的是,我将解决如何解决特定问题。到目前为止,每个解决方案似乎又带来了 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]]: recursive type parameters in case class fields
我基本上又问了同样的事情,但把问题更进一步了。你可以在这里看到 something.i 基本上和 something.i.getOne 具有相同的类型,但是这些类型不能互换使用,因此这里的对象不能一致地用作不同函数的参数。如何使此代码以 something.i 和 something.i.getOne(甚至可能是同一个对象)具有编译器和类型系统识别的相同类型的方式工作?
这个特定问题的重点在示例代码中的 testMethod4 中。