有关scala的类型参数的更多信息,试图获得对类型的一致引用 [英] more on type parameters for scala, trying to get a consistent reference to a type

查看:93
本文介绍了有关scala的类型参数的更多信息,试图获得对类型的一致引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好,所以,我之前已经问过这个问题。理想情况下,我正在寻找一个一般性的答案,可以帮助我理解如何一致地指定类型,但取而代之的是,我将着手解决特定的问题。到目前为止,每个解决方案似乎都带来了3个问题,我试图避免将整个应用程序放在此处,但我的目标是找到一种方法,以一种有用的方式从任何地方引用递归参数化特征类型的类型。一个非平凡的程序,该特征类型的值可以互换使用。

OK, so, I've asked about this before. Ideally I'm looking for a general answer that will help me understand how to specify types consistently, but in lieu of that, I'll settle for how to solve specific problems. So far each solution seems to bring 3 more issues, I'm trying to avoid putting an entire application here but my goal is to find a way to refer to the type of a recursively parameterized trait type from anywhere, in a useful way, in a non-trivial program, where values of that trait type can be used interchangeably.

因此,这里有更多示例代码:

So, here's more sample code:

//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]]
来自以下问题的答案:
递归类型参数如果是类字段

I figured out how to use the type parameter: [T <: MyTrait[T], U[X <: MyTrait[X]] <: MyTrait[X]] from an answer to this question: recursive type parameters in case class fields

,我基本上是在问同样的事情,但问题要进一步解决。您可以在此处看到something.i与some.i.getOne基本上具有相同的类型,但是这些类型不能互换使用,因此此处的对象不能始终用作不同函数的参数。我该如何以某种方式使这段代码工作,使something.i和something.i.getOne(甚至可能是同一对象)具有与编译器和类型系统所识别的相同类型?

and I'm basically asking the same thing again, but taking the problem a little further. You can see here that something.i basically has the same type as something.i.getOne, but those types can't be used interchangeably, and so the object can't be consistently used as a parameter to different functions here. How can I make this code work in a way that something.i and something.i.getOne (really probably even the same object) have the same type as recognized by the compiler and type system?

这个特定问题的实质在示例代码的testMethod4中。

The meat of this particular question is in testMethod4 in the sample code.

推荐答案

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

The pattern MyTrait[A <: MyTrait[A]] means you will want to work straight with A, and not anymore with MyTrait, as A extends this trait and guarantees to return instances of itself throughout the methods.

因此,错误是 Foo 的定义,它应该很简单:

Therefore, the mistake is the definition of Foo, it should be simply:

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

在给定的 Foo 正确的情况下,您的 MyClass 也会编译,并且还会显示客户端代码 。

With the given correction of Foo, your MyClass compiles and the 'client code', too.

此外,嵌套 U [X< ;: MyTrait [X]]之类的类型< ;: MyT rait [X]] 没有任何意义。最终,您将拥有一个表示形式。方法参数处于互变位置,因此具有类型 T< ;: MyTrait [T] 的参数就足够了,无论多么具体,您都可以使用任何表示形式。换句话说, Foo [U [T]] Foo [T] 相比没有任何优势,但是事情不必要地复杂。在所有测试方法中,基本上都可以删除 U 类型参数。

Furthermore, nesting the type like U[X <: MyTrait[X]] <: MyTrait[X]] does not make any sense. Eventually you will have one representation type. Method arguments are in contravariant position, so it totally suffices to have arguments of type T <: MyTrait[ T ] and you can stick in any representation type, no matter how specific. In other words, Foo[U[T]] doesn't have any advantage over Foo[T] but makes things unnecessarily complicated. In all your test methods you can basically remove the U type parameters.

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
}

这篇关于有关scala的类型参数的更多信息,试图获得对类型的一致引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆