Scala 模拟继承+;具有不可变对象的可变状态

Scala 模拟继承+;具有不可变对象的可变状态,scala,immutability,Scala,Immutability,我在用不可变对象建模我们的域时遇到了一个问题 可变设计 一个基本特征WObject(世界对象)和大量特征,用于执行特定操作,如OwnedObj(hp/owner/takeDamage)、Movement(movementLeft/moveTo)、Fighter(attacked/attack) 在层次结构的末尾,您有一个可变类,它混合了适当的特征: class Corvette(var position: Vect2) extends WObject with OwnedObj with Mov

我在用不可变对象建模我们的域时遇到了一个问题

可变设计

一个基本特征WObject(世界对象)和大量特征,用于执行特定操作,如OwnedObj(hp/owner/takeDamage)、Movement(movementLeft/moveTo)、Fighter(attacked/attack)

在层次结构的末尾,您有一个可变类,它混合了适当的特征:

class Corvette(var position: Vect2) extends WObject with OwnedObj with Movable with Fighter
如果用户想要执行操作(比如移动船舶),您可以执行以下操作:

不变的设计

如果moveTo必须返回一个新对象,它将返回什么类型

我试过使用
trait Movable[Self你可以用一个存在主义:
(Movable[T]with Fighter[T]for some{type T})
写你的“same\in with with”格

如果我正确理解了您的
attackReachable
示例,我就不会太担心路径依赖类型。您通常可以允许对它们进行推断,具体调用将具有“实际”属性类型。策略性地使用隐式
=:=
莱布尼兹
参数,如果您知道类型实际上是相同的,则可以防止事情失控。或者更简单地说,您可以要求类型相同:

def doSomething[T <: Moveable { type Self = T }](t: T): T =
  t.somethingThatReturnsTDotSelf()

要将此应用于列表,您可以将列表保留为HList,以便了解所有元素的类型(例如,您的列表的类型为
Fighter::Corvette::HNil
),或者在列表条目中包含带有存在主义的证据(例如
trait ObjAndMove{type T;val obj:T;val证据:Move[T]}
然后使用
列表[ObjAndMove]

attackReachable可以做两件事:1)如果目标不能被攻击,它应该只返回
数据。2)如果目标可以到达,它应该返回更新的数据,其中目标将被更改,Self将被更改,并将其标记为已攻击。由于Self类型1变得不可能,因为编译器不知道Self==data.value._2.Self(通过修改Self返回)您还可以详细说明单眼镜头和不成形镜头吗?如果您只有一个不同类型的列表(比如说基本类型的WorldObject),您如何调用moveTo?您是否必须将模式匹配到具体类型,才能启动typeclass?
def takeDamage(obj: OwnedObj): obj.Self = if (Random.nextDouble()) obj.takeDamage else obj.self
  def attackReachable(
    data: WObject.WorldObjUpdate[Self]
  ): WObject.WorldObjUpdate[data.value._2.Self]
case class WObject(position: Vect2, id: UUID=UUID.randomUUID())
case class OwnedObj(owner: Owner)
case class Movable(movementLeft: Int)
case class Fighter(attacked: Boolean)
case class Corvette(obj: WObject, owned: OwnedObj, movable: Movable, fighter: Fighter)

// Something that has both WObject and Movable
trait MovableOps[A <: ???] {
  def moveTo(obj: A, target: Vect2): A
}
val opt = objects.collectFirst { case obj: ??? if obj.position == position => obj }
opt.fold(Log.error(s"Movable at $position not found!")) { obj =>
  objects = objects - obj + obj.moveTo(position)
}
def doSomething[T <: Moveable { type Self = T }](t: T): T =
  t.somethingThatReturnsTDotSelf()
trait Move[A] {
  val lens: Lens[A, (WObject, Movable)]
}
/** This could be implicitly derived with Generic if you really want to -
or you could use Records. */
implicit def moveCorvette = new Move[Corvette] {
  val lens = lens[Corvette].obj ~ lens[Corvette].movable
}

def moveTo[A: Move](obj: A, target: Vect2) = {
  val l = Lens[A, (Wobject, Movable)]
  val remainingMoves = l.get(obj)._2.movementLeft - 1
  l.set(obj)((target, remainingMoves))
}