【问题标题】:recursive type parameters in case class fields案例类字段中的递归类型参数
【发布时间】:2012-09-07 18:01:48
【问题描述】:

好的,所以,我知道我可以做以下事情:

trait MyTrait[T <: MyTrait[T]] { self: T =>
  val listOfT: List[T]
  def getFirst: T
  def getOne: T = if (listOfT.length > 0) getFirst else self
}

class MyClass extends MyTrait[MyClass] {
  override val listOfT: List[MyClass] = List[MyClass](this)
  override def getFirst: MyClass = listOfT.head
}

如果我希望 MyTrait 有一个伴随对象,它看起来像:

object MyTrait{
  def doSomething[T <: MyTrait[T]](aninstance:T)= { ... }
}

所有这些看起来都很丑陋,我希望看到更好的方法,但是,现在我只是想弄清楚,如何从其他任何地方引用类型?例如:

case class Foo( anInstanceOfMyTrait: MyTrait[what goes here???] )

或者有没有更简单的方法?

【问题讨论】:

  • case class Foo[A](i: MyTrait[A]) 呢?
  • 好吧,然后案例类编译,但如果我从匹配器中提取 i 并尝试将 i 传递给 MyTrait.doSomething[T&lt;:MyTrait[T]](aninstance:T),我会收到错误:“推断类型参数[MyTrait[Any]] 不符合方法 doSomething 的类型参数界限 [T <: mytrait>
  • 如果我:case class Foo[A &lt;: MyTrait[A]](i:MyTrait[A]) 在尝试将i 传递给doSomething 时,我仍然得到相同的推断类型参数错误
  • 基于相同的示例代码添加了另一个类似的问题,其中包含更多问题:stackoverflow.com/questions/12337846/…

标签: scala inheritance types


【解决方案1】:

查看您的评论,实际问题似乎是在您尝试参数化 Foo 时,您两次引用了 MyTrait:

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

试试这个:

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

这反映了MyTrait.doSomething 的定义方式,因此您可以将 i 传递给 doSomething:

case class Foo[A<:MyTrait[A]](i: A)
val foo = new Foo[MyClass]( new MyClass )
MyTrait.doSomething( foo.i ) // This compiled OK

【讨论】:

  • 对我不起作用...将其更改为案例类Foo[A&lt;:MyTrait[A]](i:A) 仍然给我inferred type arguments [Any] do not conform to method doSomething's type parameter bounds [T &lt;: MyTrait[T]]
  • 我知道你的答案是什么问题......你已经指定了新的 Foo[MyClass] (所以你的代码编译)。我在定义特征的文件中,我不知道子类会在这里。我需要一个案例类来保存 MyTrait 的实例,以便在伴生对象中的方法和伴生对象中的另一个方法之间传递,因此需要能够在不了解实现类的情况下创建案例类的实例。跨度>
  • 这应该是原来的问题。你能发布一个更完整的代码 sn-p,这将完全代表你想要实现的目标吗?对于它的价值,我认为您不需要更改任何内容以“能够在不了解实现类的情况下创建案例类的实例”。只需让您的 2 个伴随对象方法是通用的。但话又说回来,请更新您的帖子,这样我们就不必假设了。
  • 我不确定为什么我无法解释这一点,但我只是想大致了解如何以非平凡的方式以一致的方式引用特征的类型程序。我给出了另一个类(碰巧是一个案例类)的一个例子,它可能希望将 trait 作为一个属性。您的回答仅显示如何引用子类,这是一个微不足道的问题。请参阅原始问题的 cmets。
  • 也许我只是不明白你的答案,这与我在另一个问题上接受的答案非常相似......不太清楚为什么我之前无法让它工作。
【解决方案2】:

我得到了这个工作:

trait MyTrait[T <: MyTrait[T]] {
  def getFirst = this
}

class MyClass extends MyTrait[MyClass]

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.getFirst
}

val mc = new MyClass
val foo = Foo(mc)
MyTrait.doSomething(foo.i)

【讨论】:

  • 现在,如果我尝试从doSomething 中调用t 上的任何方法,我就会得到那个方法is not a member of type parameter U[T]
  • 更具体的错误,如果我在doSomething的实现中将t更改为t.getOne,我得到:error: value getOne is not a member of type parameter U[T]。我需要一种更通用的方式来引用类型,我还需要能够指定返回类型,因为在我的实际应用程序中,其中一些方法是递归的。 (我正在使用具有 getOne 的原始帖子中的 MyTrait 实现)
  • @Brian:是的,我明白了。我介绍了U[X] 的上限。看起来很丑陋,但有效。我不明白你对递归方法的意思。如果此答案尚未解决您的所有问题,请编辑您的问题以说明您的所有需求。
  • 我对递归方法的全部意思是我不能在我的实际程序中省略返回类型注释。正如我对另一个答案的评论,我试图大致了解如何引用类型,案例类只是一个示例。你的回答确实处理了具体的例子,所以我会“接受”。实际上,我将重写我的程序以不使用递归类型参数。我现在对您的回答的一个问题是,如果我传递一个 U[T],其他类不会将该类型视为与 MyTrait[T] 兼容。我将针对特定的其他问题添加关于 SO 的其他问题。
猜你喜欢
  • 1970-01-01
  • 2014-12-17
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 2020-02-06
  • 1970-01-01
相关资源
最近更新 更多