【问题标题】:How to design polymorphic classes with generics如何使用泛型设计多态类
【发布时间】:2016-12-23 16:38:27
【问题描述】:

我尝试设计具有通用多态性的 api

trait GameState {
  def doIt(): Unit
}

trait GameMechanics[T <: GameState] {
  def stateHolder: StateHolder[T]
}

abstract class AbsGameMechanics[T <: GameState](sh: StateHolder[T]) extends GameMechanics[T] {
  override def stateHolder: StateHolder[T] = sh
}

class StateHolder[T <: GameState](var state: T) {
  def get: T = state
  def set(_state: T): Unit = state = _state
}

所以用户应该扩展GameStateAbsGameMechanicsGameMechanics 应该有特定类型的 GameState, DominoMechanics=>DominoGameState

用户介绍新游戏:

class DominoGameState extends GameState {
  override def doIt(): Unit = println("domino working!")
}

class DominoMechanics(sh: StateHolder[DominoGameState]) extends AbsGameMechanics[DominoGameState](sh)

val domino = new DominoMechanics(new StateHolder[DominoGameState](new DominoGameState))

在我的系统中,我应该对状态进行多态调用

def internal(gm: GameMechanics[GameState]): Unit = {
  gm.stateHolder.get.doIt()
}

它没有编译,我不明白这是什么意思:

internal(domino)

错误:(41, 11) 类型不匹配;发现:A$A133.this.DominoMechanics 必需:A$A133.this.GameMechanics[A$A133.this.GameState] 注意: A$A133.this.DominoStarting <: a trait gamemechanics t>

我做错了什么。什么?

【问题讨论】:

  • 搜索“Scala covariance”,这个问题很多。

标签: scala


【解决方案1】:

您的方法internal 只接受GameMechanics[GameState],但您尝试传入GameMechanics[DominoStarting],它不是GameMechanics[GameState] 的子类型,因为GameMechanicsT 类型中是不变的。您可能想查找有关不变性和协方差的其他一些问题,因为有很多。

但我认为您代码中的问题不一定与协方差或不变性有关。你不应该要求GameMechanics[GameState]。您已经将T 定义为必须是GameState 的子类型...如果您接受任何类型的GameMechanics,您应该这样做:

def internal[S <: GameState](gm: GameMechanics[S]): Unit = {
  gm.stateHolder.get.doIt()
}

或者当你不关心确切的类型时:

def internal(gm: GameMechanics[_ <: GameState]): Unit = {
  gm.stateHolder.get.doIt()
}

【讨论】:

    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 2017-08-20
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 2018-01-24
    • 2021-05-11
    • 1970-01-01
    相关资源
    最近更新 更多