这里不太确定标准术语,因此我会尝试描述我尝试做的事情。如果您有点好奇,我实际尝试编写的应用程序是一个类似于Resque或rq的异步任务队列。
我有TaskDef[ArgsT <: AnyVal, ResultT <: AnyVal]
类型。如果你有点好奇,TaskDef
表示&#34;如何执行一个异步任务,它接受参数类型ArgsT
和结果类型ResultT
,或者任务背后的代码& #34;
我尝试定义类型TaskInst[DefT <: TaskDef]
。如果您感到好奇,TaskInst
代表&#34; TaskDef
以及与之一起运行的相关参数,或者,一个实际的任务实例被提交到队列&#34;。 TaskInst
有两个成员,definition: DefT
和arguments
,其类型我无法用代码编写。
在英语中,我想要的约束是:&#34;对于给定的DefT
,其中DefT
是某些TaskDef[ArgsT, ResultT]
,TaskInst[DefT]
应包含DefT
和ArgsT
&#34;。也就是说,任务定义的参数类型应该与赋予任务的参数类型相匹配。
如何在Scala类型系统中表达这一点?
或者,我是否错误地为我的域建模并尝试做一些非惯用的事情?一些替代方法会更加惯用吗?
提前致谢!
编辑:
我认为我的历史自我写作Java可能会在这一点上使用未经检查的演员表。对于一些未经检查的强制转换,这绝对是可行的,只是省略TaskInst
参数的类型与嵌入的TaskDef
参数的类型之间的约束。但是,我确实想知道这是否是编译器可以执行的,并且希望没有太可怕的语法。
答案 0 :(得分:7)
将它们定义为抽象类型:
```{r}
g
```
然后使用类型投影:
trait TaskDef {
type Arguments <: AnyVal
type Result <: AnyVal
}
答案 1 :(得分:0)
@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
采用类型参数。然后,当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
的独立实例并不是真的有用。