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