我的函数缺少扩展函数的参数类型;不适用于具有相同签名的另一个

missing parameter type for expanded function for my function; not for another with same signature

简写形式:我有一个与Future.recover签名相同的方法。将部分函数传递给 Future 的版本有效。将相同的 PF 传递到我的版本会导致 missing parameter type for expanded function. The argument types of an anonymous function must be fully known. (SLS 8.5) 错误。有什么区别?

更长的形式: 我正在尝试实施 TracingFuture class 讨论的 here 以尝试跨未来边界跟踪错误。基本技术是将 Future 包装在另一个 class、TracingFuture 中,同时添加伪堆栈跟踪。

博客 post 中给出的代码缺少 Future 中的 recover 方法,因此我添加了具有相同签名的代码:

class TracingFuture[+T](underlying: Future[T], val trace: Vector[FutureTraceElement]) extends Future[T] {

  def recover[U >: T](pf: PartialFunction[Throwable, U]
                     )(implicit ec: ExecutionContext, enclosing: sourcecode.Enclosing, file: sourcecode.File,
                       line: sourcecode.Line): TracingFuture[U] = {
    val recovered = underlying.recover(pf)
    new TracingFuture[U](recovered, trace :+ FutureTraceElement(enclosing.value, "recover", file.value, line.value))

  }

}

为了进行比较,这里是 Future 中的等效代码块。请注意,除了额外的隐式参数外,签名是相同的。

trait Future[+T] extends Awaitable[T] {

  def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
    transform { _ recover pf }
}

最后,我的产生编译错误的代码:

val x: TracingFuture[Vector[Maintainer]] = ... // code producing a TracingFuture
val fMaintainers = x.recover {
  case err: Throwable ⇒
    logger.error("Failed to get list of user maintainers.", err)
    Vector.empty[Maintainer]
}

错误信息:

[error] /Users/bwbecker/oat/src/oat3/modules/wapp/app/oat/wapp/dao/CronJobDAO.scala:273: missing parameter type for expanded function
[error] The argument types of an anonymous function must be fully known. (SLS 8.5)
[error] Expected type was: ?
[error]     val fMaintainers = x.recover {
[error]                                  ^

再一次,此代码适用于 Future.recover,但我在使用 TracingFuture.recover 时遇到编译错误。我不明白为什么。

This SO question 解释说编译器知道部分函数的参数必须是 T 的超类型,但不能保证这一点。但是为什么它 运行 没有进入 Future.recover 的那个问题?

当然,我想知道除了重写匿名部分函数以使类型明确之外,我是否对此做了任何事情。

尝试替换

val fMaintainers = x.recover {
  case err: Throwable ⇒
    logger.error("Failed to get list of user maintainers.", err)
    Vector.empty[Maintainer]
}

val fMaintainers = x.recover(PartialFunction[Throwable, Vector[Maintainer]] { 
  case err: Throwable ⇒
    logger.error("Failed to get list of user maintainers.", err)
    Vector.empty[Maintainer]
})

Why do I get a "missing parameter for expanded function" in one case and not the other?

问题是 TracingFuture 有两个重载的 recover 方法:一个是您添加的,一个是您从 Future 继承的。当你只有一个时,它提供了对类型推断至关重要的预期类型,但对于重载方法它不起作用,正如你从 Expected type was: ?.

中看到的那样

您可能认为编译器应该注意到函数参数的类型是相同的,因此仍然可以提供预期的类型。你是对的,但是 it was only fixed in Scala 2.12.

当然,这样你就会 运行 遇到麻烦,因为只有隐式参数不同时,编译器无法判断你想要哪个重载。