[英]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.