首页 文章

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

提问于
浏览
1

我有一个内部案例类,特别是来自this问题的事件,并且想要匹配它,包括外部对象:

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)我可以't reference the player that originally gained life in the function and 3) I'错过直接匹配 life 这种方式 .

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

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

理想情况下,我想要类似的东西

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

这可能是某种方式,还是我可以解决这个问题?或者我是否必须使用GainLife嵌套?

2 回答

  • 5

    当你在另一个类中定义类时,意味着该类型特定于周围的类,因此,如果你想让它代表相同的东西,那么playerA.GainLife与playerB.GainLife(这被称为路径依赖类型)的类型不同您可以在与实例无关的范围内定义它:包或类的伴随对象 .

    您可以在此问题中阅读更多内容:What is meant by Scala's path-dependent types?

  • 0

    我最接近的是定义我自己的 unapply 方法:

    class Player {
      self =>
    
      var _life = 20
      def life = _life
    
      def gainLife(life: Int) = execute(GainLife(life))
    
      case class GainLife(life: Int) extends Event {
        def player = self
    
        def execute() = _life += life
      }
    }
    
    object Player {
      object _GainLife {
        def unapply(event: Player#GainLife) =
          Some((event.player, event.life))
      }
    }
    

    请注意,命名 Player._GainLife 对象 Player.GainLife 会导致名称冲突,这是最重要的缺点 . 因此,我选择从 Player 名称空间外部提供该类型:

    val GainLife = Player._GainLife
    

    这允许使用player.GainLife.unapply和Player._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 方法修复 .

相关问题