【问题标题】:type parameter with underlying type in - Scala具有基础类型的类型参数 - Scala
【发布时间】:2018-10-24 17:03:06
【问题描述】:

假设我有一个类型为A 的特征,它是Any 的子类,还有一个名为nextState 的方法,它的类型与参数相同。

trait GameEnvironment {
  type A <: Any
  def nextState(state: A, input: Int): (A, Boolean)
}

然后,这个特征被一个名为 Tetris 的类扩展,它覆盖了类型成员 A 和方法 nextState

class Tetris extends GameEnvironment {
  override type A = ((Array[Array[Int]]), Int)

  def nextState(state: (Array[Array[Int]], Int), input: Int): 
  ((Array[Array[Int]], Int), Boolean) = {


     ((state, false))
  }
}

现在在另一个名为ReinLib 的类中,我创建了一个GameEnvironment,并且我还有一个接收参数GameEnvironment#A 的函数。

class ReinLib(val mode: String) {
  val env : GameEnvironment = new Tetris()

  def simulateStep(state: GameEnvironment#A, input: Int): (Boolean) = 
    {
       env.nextState(state, input)._2
    }
}

现在如果我编译这段代码我会得到一个错误

类型不匹配 state.type(与底层类型...

据我所知,这是因为编译器不确定state 的类型。但是我似乎找不到如何解决我的问题,所以我想知道如何解决这个问题。

【问题讨论】:

    标签: scala generics types scala-generics type-members


    【解决方案1】:

    GameEnvironment#A 类型太模糊了,它本质上与env 中使用的状态类型完全无关。

    你可能想要这样的东西:

    trait GameEnvironment {
      type A
      def nextState(state: A, input: Int): (A, Boolean)
    }
    
    class Tetris extends GameEnvironment {
      override type A = ((Array[Array[Int]]), Int)
    
      def nextState(state: A, input: Int): (A, Boolean) = {
        (state, false)
      }
    }
    
    class ReinLib(val mode: String) {
      val env: GameEnvironment = new Tetris()
    
      def simulateStep(state: env.A, input: Int): Boolean = {
        env.nextState(state, input)._2
      }
    }
    

    编译成功,因为现在env.nextState可以接受state: env.A作为参数。

    【讨论】:

    • 我不完全相信这会奏效...你能举一个打电话给simulateStep的例子吗?例如:new ReinLib("").simulateStep((Array(Array(1, 2, 3)), 0), 0) 不会编译。我想您可能需要将 A 设为泛型类型参数而不是类型成员,或者将 env 更改为 val env: Tetris = new Tetris()
    • 我之前尝试过这个,但我无法让它工作,因为 env 之前是 var 而不是 val。感谢您的帮助编辑:至少对我来说,它确实与更改一起编译,所以它似乎至少可以工作。
    • @JoeK 一旦你将具体类型 Tetris 隐藏在一般类型 env: GameEnvironment 下,你将失去从外部传递任何具体数组的能力,因为它也可能是 env: GameEnvironment = if (math.random &lt; 0.5) new Tetris() else new Quake() .因此,state: env.A 必须由GameEnvironment 本身提供。实际上,该界面不完整且不是很有用,因为它缺少“基本案例”。只要您在GameEnvironment 中有def initState: A,它就会更有意义。
    • 好的,是的,这是有道理的。我的观点确实是关于从外部传递状态,但如果不需要,并且状态始终是该类的内部,那很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2020-03-27
    相关资源
    最近更新 更多