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