Scala for推导式匹配多case class时提取Trigger参数方案求教
解决方案
方案1:在sealed trait中定义统一访问方法(推荐,侵入性低易维护)
先修改Event trait的定义,增加默认返回None的triggerOpt方法,只有携带Trigger的子类重写该方法:
sealed trait Event { // 统一返回可选类型的Trigger,无该字段的子类默认返回None def triggerOpt: Option[Trigger] = None } object MyTrait { final case class EventA(context: Context) extends Event // 带Trigger的子类重写方法返回对应值 final case class EventB(trigger: Trigger) extends Event { override def triggerOpt: Option[Trigger] = Some(trigger) } final case class EventC(trigger: Trigger) extends Event { override def triggerOpt: Option[Trigger] = Some(trigger) } final case class EventD(trigger: Option[Trigger] = None) extends Event { override def triggerOpt: Option[Trigger] = trigger } // 其余不带Trigger的子类无需修改,直接继承默认实现 final case class EventZ(factor: Factor) extends Event }
之后直接在原逻辑中调用triggerOpt即可,根据你的业务需求处理无Trigger的场景:
import cats.Monad // 假设你的for推导使用的效应类型为F(如IO、Either等) import cats.implicits._ event match { case ev @(_: EventA | _: EventB | _: EventC | _: EventD) => val amount = for { count1 <- countThis count2 <- countThat // 有Trigger时调用方法,无Trigger时直接返回成功的空值 _ <- ev.triggerOpt.fold(Monad[F].unit)(handleSomeTypeOfEvent) } yield res + another case _ => doSomethingElse() }
如果不需要兼容cats,也可以手动判断triggerOpt是否为空,对应返回你的效应类型的成功值即可。
方案2:使用独立提取器(无侵入,适合无法修改原有类定义的场景)
如果你不能修改Event及其子类的定义,可以自定义提取器统一提取Trigger:
// 独立定义Trigger提取器,不侵入原有类结构 object TriggerExtractor { def unapply(event: Event): Option[Trigger] = event match { case EventB(trigger) => Some(trigger) case EventC(trigger) => Some(trigger) case EventD(Some(trigger)) => Some(trigger) case _ => None } }
原有业务逻辑只需增加一行提取Trigger的代码即可:
event match { case ev @(_: EventA | _: EventB | _: EventC | _: EventD) => // 用提取器统一获取Trigger val triggerOpt = ev match { case TriggerExtractor(t) => Some(t) case _ => None } val amount = for { count1 <- countThis count2 <- countThat _ <- triggerOpt.fold(Monad[F].unit)(handleSomeTypeOfEvent) } yield res + another case _ => doSomethingElse() }
两种方案都不需要拆分原有的匹配分支,也不需要重复编写for推导逻辑,完全满足需求。
内容的提问来源于stack exchange,提问作者Cypherius
相关产品推荐
相关产品推荐

