scala - 可以解决类型类证据参数和具体实例参数之间的类型冲突吗?
问题描述
在有没有办法保证 Scala 中的类型类存在案例类复制方法?,我在这个新问题出现的地方提出了一个相关的问题。不幸的是,由于不明原因,我需要类型参数。
我的类型类和隐式操作类看起来像:
trait Job[J] {
def id(jb: J): JobId
def cmd(jb: J): String
type M <: JobMetaData
type JRef = J
def meta(jb: J): M
def pickler: Pickler[J]
def rw: RW[J]
def instance(jb: J, id: JobId, cmd: String, meta: M): J
}
object Job{
type Aux[J0, M0] = Job[J0] {type M = M0}
implicit class JobDispatch[J](val job: J)(implicit val ev: Job[J]) {
def id: JobId = ev.id(job)
def cmd: String = ev.cmd(job)
def meta: ev.M = ev.meta(job)
def rw: RW[J] = ev.rw
def copyJob(
idIn: JobId = job.id,
cmdIn: String = job.cmd,
metaIn: ev.M = job.meta
): J = ev.instance(job, idIn, cmdIn, metaIn)
}
}
值得注意的是instance
和copyJob
方法;copyJob
旨在成为公共 API。
现在举一个具体的例子,我有:
final case class OneShot(id: JobId, cmd: String, meta: SysJobMetaData) {
type M = SysJobMetaData
}
object OneShot{
implicit val rw: RW[OneShot] = macroRW
implicit val jobOneShot: Job.Aux[OneShot, SysJobMetaData] = new Job[OneShot] {
def id(jb: OneShot): JobId = jb.id
def cmd(jb: OneShot): String = jb.cmd
override type M = SysJobMetaData
def meta(jb: OneShot): M = jb.meta
val pickler: Pickler[OneShot] = generatePickler
val rw: RW[OneShot] = OneShot.rw
def instance(jb: OneShot, id: JobId, cmd: String, meta: M): OneShot =
jb.copy(id, cmd, meta)
}
但这给出了错误:
[error] /home/brandon/workspace/CCRS/model/src/main/scala/org/xsede/jobrunner/model/ModelApi.scala:277: type mismatch;
[error] found : _1.ev.M where val _1: org.xsede.jobrunner.model.ModelApi.Job.JobDispatch[J]
[error] required: JobDispatch.this.ev.M
[error] metaIn: ev.M = job.meta
[error] ^
首先,我不认为我完全理解错误。似乎job.meta
应该解决 type ev.M
。这可以解决吗?
编辑 1
如果我在asInstanceOf
定义copyJob
(,但原来的类可能没有恢复,包括出现在扩展类中的成员,如下所示:= ev.instance(job, idIn, cmdIn, metaIn.asInstanceOf[ev.M])
M <: JobMetaData
JobMetaData
shell
value shell is not a member of _1.ev.M
[error] val resultMaybe: Try[CommandResult] = cmd.meta.shell match {
[error] ^
解决方案
我可能在这里遗漏了一些东西,因为发生了很多事情,但看起来隐式转换JobDispatch
正在递归调用自身。你为什么不这样做呢?直接调用meta
,而不是job.meta
.
trait Job[J] {
def id(jb: J): JobId
def cmd(jb: J): String
type M <: JobMetaData
type JRef = J
def meta(jb: J): M
def pickler: Pickler[J]
def rw: RW[J]
def instance(jb: J, id: JobId, cmd: String, meta: M): J
}
object Job{
type Aux[J0, M0] = Job[J0] {type M = M0}
implicit class JobDispatch[J](val job: J)(implicit val ev: Job[J]) {
def id: JobId = ev.id(job)
def cmd: String = ev.cmd(job)
def meta: ev.M = ev.meta(job)
def rw: RW[J] = ev.rw
def copyJob(
idIn: JobId = id,
cmdIn: String = cmd,
metaIn: ev.M = meta
): J = ev.instance(job, idIn, cmdIn, metaIn)
}
}
推荐阅读
- machine-learning - 机器学习中的“性能度量 P”和“评估”有什么区别?
- ios - ARKit 获取 ARPlaneAnchor 顶点世界坐标
- javascript - 与应用程序路由和组件共享本地化包
- python - 使用 xlwings 密码保护特定的 Excel 工作表?
- python - 在 python 中构建字典
- machine-learning - 在网格搜索 (ANN) 中为超参数使用连续值
- javascript - 如何从反应状态中删除特定项目
- azure - 如何将 Azure IoT Hub 与 Flutter App 连接起来
- sql-server - 在工作室中使用 VB 更新 SQL 数据库
- c - feraiseexcept:编译器之间的不同行为以及缺乏实现定义行为的文档