更多关于scala的类型参数,尝试获得对类型的一致引用



好吧,我以前问过这个问题。理想情况下,我正在寻找一个通用的答案,它将帮助我理解如何一致地指定类型,但除此之外,我将解决如何解决特定问题。到目前为止,每个解决方案似乎又带来了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]]&ltMyTrait[X]从这个问题的答案来看:事例类字段中的递归类型参数

我基本上又问了一次同样的问题,但把问题再进一步。你可以在这里看到,something.i基本上与something.i.getOne具有相同的类型,但这些类型不能互换使用,因此对象不能一致地用作不同函数的参数。我如何让这些代码以一种方式工作,即something.I和something.I.getOne(实际上甚至可能是同一个对象)具有编译器和类型系统识别的相同类型?

这个特定问题的核心在示例代码中的testMethod4中。

模式MyTrait[A <: MyTrait[A]]意味着您将希望直接使用A,而不再使用MyTrait,因为A扩展了这一特性,并保证在整个方法中返回其自身的实例。

因此,错误在于Foo的定义,它应该简单地为:

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

Foo进行给定的更正后,您的MyClass也会编译"客户端代码"。


此外,嵌套U[X <: MyTrait[X]] <: MyTrait[X]]这样的类型没有任何意义。最终,您将拥有一个表示类型。方法参数处于相反的位置,因此具有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
}

相关内容

  • 没有找到相关文章

最新更新