Scala:如何模式匹配内部case类的封闭对象?

Scala:如何模式匹配内部case类的封闭对象?,scala,pattern-matching,case-class,Scala,Pattern Matching,Case Class,我有一个内部case类,特别是一个来自question的事件,并希望匹配它,包括外部对象: class Player { var _life = 20 def life = _life def gainLife(life: Int) = execute(GainLife(life)) case class GainLife(life: Int) extends Event { def execute() = _life += life } } 我可以很容易地编写

我有一个内部case类,特别是一个来自question的事件,并希望匹配它,包括外部对象:

class Player {
  var _life = 20
  def life = _life

  def gainLife(life: Int) = execute(GainLife(life))

  case class GainLife(life: Int) extends Event {
    def execute() = _life += life
  }
}
我可以很容易地编写一个效果部分函数来代替特定玩家的生活事件:

//gain twice as much life
def effect(player: Player): ReplacementEffect = {
  case player.GainLife(x) => player.GainLife(x * 2)
}
然而,我不能为其他球员做同样的事情。最接近我的是:

//only you gain life
def effect2(player: Player): ReplacementEffect = {
  case evt: Player#GainLife => player.GainLife(evt.life)
}
但是1这会用一个新的生命增益替换你自己的生命增益,2我不能引用最初在函数中获得生命的玩家,3我错过了直接匹配生命的方式

这可以使用与路径无关的类型来表示,如

case Player.GainLife(_player, life) if _player != player => GainLife(player, life)
理想情况下,我想要像这样的东西

case _player.GainLife(life) if _player != player => player.GainLife(life)

这是可能的,还是我可以解决这个问题?或者我必须使GainLife嵌套吗?

当您在另一个类中定义该类时,意味着该类型特定于周围的类,因此,playerA.GainLife与playerB.GainLife不是同一类型。如果您希望它的含义与您在相同的范围内定义它的内容相同,则称为路径依赖类型,无论实例是什么:包还是类的伴生对象


您可以在这个问题中阅读更多内容:

当您在另一个类中定义该类时,意味着该类型特定于周围的类,因此,playerA.GainLife与playerB.GainLife不是同一类型。如果您希望它的含义与您在相同的范围内定义它的内容相同,则称为路径依赖类型,无论实例是什么:包还是类的伴生对象


您可以在这个问题中阅读更多内容:

我最近的一次尝试是定义我自己的unapply方法:

请注意,命名玩家。_gainlifeobject Player.GainLife会导致名称冲突,这是最重要的缺点。因此,我选择从播放器名称空间之外提供该类型:

val GainLife = Player._GainLife
这允许同时使用player.GainLife.unapply和player进行匹配。\u GainLife.unapply以简洁的方式:

//gain twice as much life
def effect1(player: Player): ReplacementEffect = {
  case player.GainLife(life) => player.GainLife(life * 2)
}

//only you gain life
def effect2(player: Player): ReplacementEffect = {
  case GainLife(_player, life) if _player != player => player.GainLife(life)
}

//all players gain twice as much life
def effect3: ReplacementEffect = {
  case GainLife(player, life) => player.GainLife(life * 2)
}

最后两个示例看起来有点不对称,但如果需要,可以使用apply方法解决。

最近的一个例子是定义我自己的unapply方法:

请注意,命名玩家。_gainlifeobject Player.GainLife会导致名称冲突,这是最重要的缺点。因此,我选择从播放器名称空间之外提供该类型:

val GainLife = Player._GainLife
这允许同时使用player.GainLife.unapply和player进行匹配。\u GainLife.unapply以简洁的方式:

//gain twice as much life
def effect1(player: Player): ReplacementEffect = {
  case player.GainLife(life) => player.GainLife(life * 2)
}

//only you gain life
def effect2(player: Player): ReplacementEffect = {
  case GainLife(_player, life) if _player != player => player.GainLife(life)
}

//all players gain twice as much life
def effect3: ReplacementEffect = {
  case GainLife(player, life) => player.GainLife(life * 2)
}

最后两个示例看起来有点不对称,但如果需要,可以使用apply方法解决。

我想我看到了您的方向,但这并不完全是我想要的。我很高兴GainLife取决于受影响的玩家,我只想在模式匹配时使用该玩家。我已经在问题中添加了我认为你的建议,但这正是我想要避免的,因为我认为依赖路径的GainLife实际上更干净,这将是添加同伴对象的唯一原因。我找到了一种我觉得相当满意的方法,如果你有任何改进,你介意提出一些建议吗?我觉得这一切都有点奇怪,但也许我只是不太明白你想要实现什么。如果路径依赖类型强制您创建自定义的特殊unapply,我可能只会创建一个不依赖于路径的GainLife事件,并只向其中添加所需的所有数据,而不是此数据。我想这是一个品味的问题。我同意这很奇怪,但这几乎是对我问题的直接回答,所以我还是想和大家分享。但也有一些好处:访问私有[this]字段,无需编写播放器。在execute方法中,或在创建事件时使用。我觉得我的变体有点罗嗦,但只在一个位置,即同伴对象。客户端代码,包括特效、gainLife和execute,在我看来更好看。但我可能想得太多了。我想我知道你要往哪个方向走,但这并不完全是我想要的。我很高兴GainLife取决于受影响的玩家,我只想在模式匹配时使用该玩家。我已经在问题中添加了我认为你的建议,但这正是我想要避免的,因为我认为依赖路径的GainLife实际上更干净,这将是添加同伴对象的唯一原因。我找到了一种我觉得相当满意的方法,如果你有任何改进,你介意提出一些建议吗?我觉得这一切都有点奇怪,但也许我只是不太明白你想要实现什么。如果路径依赖类型强制您创建自定义的特殊unapply,我可能只会创建一个不依赖于路径的GainLife事件,并只向其中添加所需的所有数据,而不是此数据。我想这是一个品味的问题。我同意这很奇怪,但这几乎是对我问题的直接回答,所以我还是想和大家分享。然而,也有一些好处:获得公共关系 ivate[此]字段,无需编写播放器。在execute方法中,或在创建事件时使用。我觉得我的变体有点罗嗦,但只在一个位置,即同伴对象。客户端代码,包括特效、gainLife和execute,在我看来更好看。但我可能想得太多了。