繁体   English   中英

强制类型参数为特征

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM