[英]Force type parameter to be a trait
我有以下代碼;
object main
{
def main(args: Array[String]): Unit =
{
trait E
{
def test(): Unit = println("test :)")
}
class B[T](val x: Int)
{
def inc(): B[T] with T = new B[T](x + 1) with T
}
class A[T](f : B[T] with T => Unit)
{
def apply(b: B[T] with T) = f(b)
}
val b = new B[E](0) with E
val a = new A[E](b => b.test())(b)
}
}
但是, def inc(): B[T] with T = new B[T](x + 1) with T
的行def inc(): B[T] with T = new B[T](x + 1) with T
不能編譯,給出“需要類類型但是找到T類”和“T需要”的錯誤混合的特質“。 我明白為什么會這樣,但我找不到辦法解決它! 我還沒有找到一種方法來限制T
成為一種特質,這讓我擔心這種方法不起作用......
為了給出更多關於我為什么要實現這個目標的背景(只是任何人都可以提供更好的解決方案)我有一個Parsec[S, U, E, A]
類,它由接受State[S, U, E] with E
的函數構成State[S, U, E] with E
對象。 這個想法是U
是用戶給定的狀態, A
是解析器的結果, S
是令牌流, E
是狀態的某種擴展(例如,人們可能希望創建Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]]
U = Int
將是用戶想要計數的東西,並且不需要干擾壓痕靈敏度所需的狀態(這是兩個Ints) Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]]
等等。這將通過混合IndentationSensitive
特性提供。然后,如果用戶想要一些其他功能,他們可以繼續混合解析器的更多特征。
那么,無論如何我可以約束代碼中的類型參數T
,這樣我就可以將它混合成B
,或者如果沒有,是否有更好的方法來完成我需要的東西?
如果真的不清楚什么,我試圖完成,然后這對代碼審查問題的說明(在很多更詳細)的情況。 但是Parsec[S <: Stream[_, _], U, A]
被Parsec[S <: Stream[_, _], U, E, A]
取代,而State和所有其他部分則相同。
為了給出更多關於我為什么要實現這個目標的背景(只是任何人都可以提供更好的解決方案)我有一個
Parsec[S, U, E, A]
類,它由接受State[S, U, E] with E
的函數構成State[S, U, E] with E
對象。 這個想法是U是用戶給定的狀態,A是解析器的結果,S是令牌流,E是狀態的某種擴展(例如,人們可能希望創建Parsec[Stream[String, Char], Int, IndentationSensitive, List[Expr]]
在這種情況下,我只需添加一個val extension: E
領域的State
和轉變職能,接受State[S, U, E]
如果你真的想要,你可以添加從State[S, U, E]
到E
的隱式轉換,這樣函數可以直接訪問E
的成員,但我可能不會自己做。
我已經設法找到問題的解決方案,它並不理想,但它確實解決了系統的其他幾個問題。 也就是說,當我們創建了一個new State[S, U, E](input, pos, state) with E
指的是什么與添加的變量發生E
。 他們迷路了,這是一個殺手。
讓我們定義一個新的類型type StateBuilder[S <: Stream[_, _], U, E] = (Option[State[S, U, E] with E], S, SourcePos, U) => State[S, U, E] with E
這個函數可以構造一個我們想要的新狀態,給定一個可能的先前狀態和一些狀態的“正常”參數的新值。
現在我們可以將國家重新定義為;
case class State[S <: Stream[_, _], U, E](stateInput: S, statePos: SourcePos, stateUser: U, build: StateBuilder[S, U, E])
現在我們只需要一些StateBuilder[S, U, E]
,它們將在狀態之間傳遞,但我們需要在創建初始狀態時將其輸入。 這很好,但這意味着用戶需要了解它們是什么(這有點不利)。 沒有擴展的示例構建器;
trait Default
object Default
{
def build[S <: Stream[_, _], U](s: Option[State[S, U, Default] with Default], ts: S, pos: SourcePos, u: U): State[S, U, Default] with Default =
{
new State[S, U, Default](ts, pos, u, build) with Default
}
}
一個更復雜的可能是;
trait IndentationSensitive
{
var stateLevel: Int = 0
var stateRequiredIndent: Int = 0
}
object IndentationSensitive
{
def build[S <: Stream[_, _], U](s: Option[State[S, U, IndentationSensitive] with IndentationSensitive], ts: S, pos: SourcePos, u: U): State[S, U, IndentationSensitive] with IndentationSensitive =
{
val s_ = new State[S, U, IndentationSensitive](ts, pos, u, build) with IndentationSensitive
s match
{
case Some(s) =>
s_.stateLevel = s.stateLevel
s_.stateRequiredIndent = s.stateRequiredIndent
case None =>
s_.stateLevel = 0
s_.stateRequiredIndent = 0
}
s_
}
}
為了組成擴展,用戶需要手工構建構建器功能,但任何人都無法理解如何操作並不是不合理的。 能夠為每種類型自動構建這些都會很好,但這是一個不同的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.