Scala是否可以推断传递到依赖类的泛型类型的类型?

时间:2017-01-20 03:56:16

标签: scala

鉴于以下内容:

trait A[X] {
  def foo(): X
}

class B[T <: A[_]] {
  def getFoo(a:T) = a.foo()
}

class C[T <: A[Z], Z] {
  def getFoo(a:T):Z = a.foo()
}

是否有可能使B像C一样工作?具体来说是获取a.foo()的结果类型。

scala> var b:B[A[Int]] = new B[A[Int]]()

scala> b.getFoo(AA(1))
res0: Any = 1

scala> var c:C[A[Int],Int] = new C[A[Int],Int]()
c: C[A[Int],Int] = C@4cc36c19

scala> c.getFoo(AA(1))
res1: Int = 1

b返回Any,但c正确返回Int。这显然是一个人为的例子,但如果我可以从Generic类型中提取子类型,它将通过代码大大简化。基本上,了解&#34; Z&#34; (在C中使用),而不必明确地传递它 - 从A的类型推断。

显然,C可以根据需要运行,但问题是我的框架更类似于:

class D[T <: A[Z1], U <: B[Z2], Z1, Z2] extends E[T,U,Z1,Z2]

然后要求框架的用户使用4个类型参数实现,理想情况下它只是2

class D[T <: A[_], U <: B[_]] extends E[T,U]

不是阻止程序,只是尝试简化公开的API。

1 个答案:

答案 0 :(得分:2)

您可以执行以下某些基于类型类的库中经常使用的内容:

trait Foo[H[_] <: Langh[_]]{
  def thing[A](ha: H[A]): A = ha.ha()
}

这会将type参数的解析推送到方法thing的调用。它使用更高级的类型。

事实上,如果你看一下像ScalaZ这样的库,你会看到这种模式:

trait Functor[F[_]]{
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

回复评论

无法使用U <: T[_]类型,然后能够提取实际T[A]的类型参数,因为它的定义会丢失该信息。如果以上内容对您不起作用,那么我建议输入类:

trait Foo[U]{
  def doStuff(u: U)(implicit ev: MyTypeClass[U]): ev.A = //...
}

其中您只定义MyTypeClass隐含,如下所示:

trait Whatever[FA]{ /*...*/ }

object Whatever{
  implicit def WhateverMTC[F[_] <: Bound[_], A0] = new MyTypeClass[F[A0]]{
    type A = A0
    //...
   }
 }

然后你可以将你的类型绑定在隐式上,你的隐式携带约束,你的类型必须更高 - 并且你可以得到一个方法,在调用站点声明返回内部“隐藏”类型。 / p>

也就是说,当第一个建议更优雅,更清晰地处理问题时,这是很多机器。