泛型类型边界的问题

时间:2015-01-26 15:26:29

标签: scala

我有以下特点:

trait Recoverable[M[_]] {
    def recoverW[T, U >: T](f: PartialFunction[Throwable, M[U]])(implicit executor: ExecutionContext): M[U]
    def fail[T](error: Throwable): M[T]
}

此外,我在同一个包中有一个隐式转换方法:

implicit def tryRecoverable[T](`try`: Try[T]) = new Recoverable[Try] {
    override def recoverW[T, U >: T](f: PartialFunction[Throwable, Try[U]])(implicit executor: ExecutionContext): Try[U] = `try`.recoverWith[U](f)
    override def fail[T](error: Throwable): Try[T] = Failure(error)
  }

此代码无法编译抱怨

type arguments [U] do not conform to method recoverWith's type parameter bounds [U >: T]
    override def recoverW[T, U >: T](f: PartialFunction[Throwable, Try[U]])(implicit executor: ExecutionContext): Try[U] = `try`.recoverWith[U](f)
                                                                                                                                            ^

为什么这段代码不能编译?

1 个答案:

答案 0 :(得分:2)

因为T内的recoverWT内的tryRecoverable - 是不同的T([T, ...]定义了新的方法范围T),所以可以:

trait Recoverable[M[_]] {
    type TT
    def recoverW[U >: TT](f: PartialFunction[Throwable, M[U]])(implicit executor: ExecutionContext): M[U]
    def fail(error: Throwable): M[TT]
}

implicit def tryRecoverable[T](`try`: Try[T]) = new Recoverable[Try] {
    type TT = T
    override def recoverW[U >: T](f: PartialFunction[Throwable, Try[U]])(implicit executor: ExecutionContext): Try[U] = `try`.recoverWith[U](f)
    override def fail(error: Throwable): Try[T] = Failure(error)
}

但我不会在这里使用M[_]定义,因为它主要用于您可以在方法中实际构建M[_]的内容,例如:

trait Monad[M[_]] extends Applicative[M] {
  def flatMap[T, U](m: M[T])(fn: (T) => M[U]): M[U]
  ...
}

例如,请参阅Twitter的Monad。实际上,使用M[_]更多是Haskell风格,因为没有classess,所以monad本身作为参数传递给方法。所以也许你根本不会使用它并直接指定trait Recoverable[M[T]]

或者你可以做Haskell风格:

trait Recoverable[M[_]] {
    def recoverW[T, U >: T](m: M[T])(f: PartialFunction[Throwable, M[U]])(implicit executor: ExecutionContext): M[U]
    def fail[T](m: M[T])(error: Throwable): M[T]
}   

implicit val tryRecoverable = new Recoverable[Try] {
    override def recoverW[T, U >: T](`try`: Try[T])( f: PartialFunction[Throwable, Try[U]])(implicit executor: ExecutionContext): Try[U] = `try`.recoverWith[U](f)
    override def fail[T](`try`: Try[T])( error: Throwable): Try[T] = Failure(error)
 }

然后将其用作:

 scala> implicitly[Recoverable[Try]].recoverW(Try{"aaaa"})({case x => Try{"bbb"}})
 res54: scala.util.Try[String] = Success(aaaa)

或者只需要在函数/类中使用Try[T]: Recoverable语法糖:

 def recover[T, Try[T]: Recoverable](t: Try[T]) = recoverW(t) _