繁体   English   中英

如何定义一个函数来接受所有扩展公共基类型的类型(Scala,下面的特定代码)?

[英]How can I define a function to accept all the types which extend a common base type (Scala, specific code below)?

我在下面的代码块中正确定义我的类型时遇到问题。

我想要做什么:我试图定义一个名为processMyFuncResult的通用函数,它接受另一个函数(工作函数)的结果,一个在计算成功时要调用的函数,以及一个要在其上调用的函数失败。 我的意图是拥有许多不同类型的工作函数,其结果在内容上是可变的,但应该扩展特征MyFuncResult[T]

问题:

在下面的代码中,我生成了一个编译错误,在为此苦苦挣扎之后,似乎无法找到一个可行的解决方案,我可以将上下文的特定子类型和结果传递给 OnSuccess 和 OnFailure 函数。

我试过在结果处理函数中引入新的类型参数并弄乱边界和方差,前者具有将相同问题推送到processMyFuncResult主体的效果,而后者似乎没有效果,但是我已经用尽了我的调整无济于事。

编译错误:

Error:(37, 41) type mismatch;
found   : (Int, WorkerContext) => Unit
required: (?, MyFuncContext) => Unit
processMyFuncResult(exampleComputation, printWorkerSuccess, printWorkerFailure)

Error:(37, 61) type mismatch;
found   : (CouldntDoitError, WorkerContext) => Unit
required: (MyError, MyFuncContext) => Unit
processMyFuncResult(exampleComputation, printWorkerSuccess, printWorkerFailure)

代码:

// ErrorTypes
trait MyError
case class CouldntDoitError(msg: String) extends MyError

// Context for passing more information to post-processing function
trait MyFuncContext
case class WorkerContext(passedArg: Int) extends MyFuncContext

// Traits / Types for Worker func results - all workers should return this kind of result
trait WorkerFuncResult[T] {
  def result: Either[MyError, T]
  def context: MyFuncContext
}

case class WorkerResult(result: Either[MyError, Int], context: MyFuncContext) extends WorkerFuncResult[Int]

// Processing function which does the interesting work and returns a WorkerFuncResult
// There are many of these which have specific types which they return (e.g. WorkerResult)
def workerFunc(a: Int): WorkerResult = {
  val compRes = for {
                  res1 <- if (a < 10) Left(CouldntDoitError("Less than 10 ")) else Right(a * 2)
                  res2 <- if (a < 30) Left(CouldntDoitError("almost made it but didn't")) else Right(res1 * 100)
                } yield res2

  WorkerResult(compRes, WorkerContext(a))
}

// Post-processing function - takes a result and invokes an on success function or on failure function 
// On the appropriate result or error
def processMyFuncResult[T](computationResult: WorkerFuncResult[T],
                           onSuccess: (T, MyFuncContext) => Unit,
                           onFailure: (MyError, MyFuncContext) => Unit) =
  computationResult.result match {
    case Right(v) => onSuccess(v, computationResult.context)
    case Left(e) => onFailure(e, computationResult.context)
  }


// Example On Success function
def printWorkerSuccess(res: Int, c: WorkerContext): Unit = println(s"Successful result was $res. " +
  s"Original arg was ${c.passedArg}")

// Example on failure function
def printWorkerFailure(res: CouldntDoitError, c: WorkerContext): Unit = println(s"Couldn't do it msg: ${res.msg}. " +
  s"Original arg was ${c.passedArg}")

// Running the computation and processing the result 
val exampleComputation = workerFunc(3)
processMyFuncResult(exampleComputation, printWorkerSuccess, printWorkerFailure)

这里有很多 - 感谢您的帮助。

问题是,如果你有一个值

trait WorkerFuncResult[T] {
  def result: Either[MyError, T]
  def context: MyFuncContext
}

和一个函数CouldntDoitError => Something ,它不能处理结果中的所有错误——它可能包含一个不是CouldntDoitError的错误。

如果您希望能够在您的类型中表达您想要处理的内容,您将需要改进您的类型。 在您的情况下,您需要两个额外的类型参数:

trait WorkerFuncResult[T, E <: MyError, C <: MyFuncContext] {
      def result: Either[E, T]
      def context: C
    }

case class WorkerResult[E <: MyError](result: Either[E, Int], context: WorkerContext) extends WorkerFuncResult[Int, E, WorkerContext]

// Processing function which does the interesting work and returns a WorkerFuncResult
// There are many of these which have specific types which they return (e.g. WorkerResult)
def workerFunc(a: Int): WorkerResult[CouldntDoitError] = {
  val compRes = for {
    res1 <-
      if (a < 10) Left(CouldntDoitError("Less than 10 "))
      else Right(a * 2)
    res2 <-
      if (a < 30) Left(CouldntDoitError("almost made it but didn't"))
      else Right(res1 * 100)
  } yield res2

  WorkerResult(compRes, WorkerContext(a))
}

// Post-processing function - takes a result and invokes an on success function or on failure function
// On the appropriate result or error
def processMyFuncResult[T, E <: MyError, C <: MyFuncContext](
    computationResult: WorkerFuncResult[T, E, C],
    onSuccess: (T, C) => Unit,
    onFailure: (E, C) => Unit
) =
  computationResult.result match {
    case Right(v) => onSuccess(v, computationResult.context)
    case Left(e)  => onFailure(e, computationResult.context)
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM