[英]Scala type system, constrain member's type by parameter of own type
这里不太确定标准术语,所以我会试着描述我想要做的事情。 如果您感到好奇,我实际上尝试编写的应用程序是一个类似于Resque或rq的异步任务队列。
我有一个类型TaskDef[ArgsT <: AnyVal, ResultT <: AnyVal]
。 如果你很好奇, TaskDef
代表“如何执行一个异步任务,它接受参数类型ArgsT
和结果类型ResultT
,或者任务背后的代码”。
我正在尝试定义一个类型TaskInst[DefT <: TaskDef]
。 如果你很好奇, TaskInst
代表“一个TaskDef
和相关的参数来运行它,或者,一个实际的任务实例被提交到队列”。 TaskInst
有两个成员, definition: DefT
和我不能在代码中写入的类型的arguments
。
在英语中,我期望的约束是:“对于给定的DefT
,其中DefT
是一些TaskDef[ArgsT, ResultT]
, TaskInst[DefT]
应该包含DefT
和ArgsT
”。 也就是说,任务定义的参数类型应该与给予任务的参数类型相匹配。
如何在Scala类型系统中表达这一点?
或者,我是否错误地为我的域建模并尝试做一些非惯用的事情? 一些替代方法会更加惯用吗?
提前致谢!
编辑:
我认为我的历史自我写作Java可能会在这一点上使用未经检查的演员表。 对于一些未经检查的强制转换,这肯定是可行的,只是省略了TaskInst
参数类型与嵌入式TaskDef
参数类型之间的约束。 但是,我确实想知道这是否是编译器可以强制执行的,并且希望没有太可怕的语法。
将它们定义为抽象类型:
trait TaskDef {
type Arguments <: AnyVal
type Result <: AnyVal
}
然后使用类型投影:
trait TaskInst[DefT <: TaskDef] {
def definition: DefT
def arguments: DefT#Arguments
}
@rightfold给出的答案的附加内容:
如果您希望始终使用类型参数,则需要将类型参数正确传递给类型构造函数。
对不起,我这样说有点含糊不清,所以让我用我当前的代码作为一个具体的例子。
trait TaskDef[ArgT_, ResT_] {
type ArgT = ArgT_
type ResT = ResT_
val name: String
def exec(arg: ArgT): String \/ ResT
}
class TaskInst[ArgT, ResT, DefT <: TaskDef[ArgT, ResT]] (
val id: UUID,
val defn: DefT,
val arg: ArgT
)
我当前代码与@ rightfold示例的主要TaskDef
在于TaskDef
采用类型参数。 然后,当TaskInst
的声明引用TaskDef
,它必须为类型构造函数提供适当的类型。
我最初错误地传递了占位符。 也就是说,我正在编写class TaskInst[DefT <: TaskDef[_, _]
。 事实证明,这并不意味着我的意思。 (我不知道。也许其他人可能倾向于遵循同样的思路。所以,这只是一个警告而不是。)不要这样做,因为那时scalac
会将预期解释为生成的占位符(正如您可能想象的那样,没有任何内容匹配),然后您会得到如下所示的模糊错误消息。
[error] /Users/mingp/Code/scala-redis-queue/src/main/scala/io/mingp/srq/core/TaskInst.scala:8: type mismatch;
[error] found : TaskInst.this.arg.type (with underlying type _$1)
[error] required: _$1
[error] val arg: DefT#ArgT_
[error] ^
[error] one error found
只是张贴这个,希望未来的读者不会陷入我所做的同一个洞。
编辑:
作为进一步的补充,既然我已经尝试了一天,我的印象是这对于异步任务来说实际上并不是一个好的数据模型。 你最好合并,因为TaskDef
的独立实例并不真正有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.