Я хочу иметь возможность динамически выбирать, какие экстракторы использовать в моем сопоставлении шаблонов классов.Передача экстракторов динамически для сопоставления с образцом
Я хочу что-то вроде:
def handleProcessingResult(extract: SomeType) : PartialFunction[Event, State] = {
case Event(someEvent: SomeEvent, extract(handlers)) =>
...
case Event(otherEvent: OtherEvent, extract(handlers)) =>
...
}
Идея заключается в том, что у меня может быть выше частичную функцию, а затем можно использовать в любом месте, где я знаю, как написать unapply
, чтобы соответствовать и извлечь handlers
из какой-то шаблон согласованный тип.
Если вам интересно, почему я хочу эти частичные функции, это значит, что я могу составлять частичные функции общего поведения вместе, чтобы сформировать обработчики для моих состояний в FK Akka. Это не требуется, чтобы понять этот вопрос, но, к примеру:
when(ProcessingState) {
handleProcessingResult(extractHandlersFromProcessing) orElse {
case Event(Created(path), Processing(handlers)) =>
...
}
}
when(SuspendedState) {
handleProcessingResult(extractHandlersFromSuspended) orElse {
case Event(Created(path), Suspended(waiting, Processing(handlers))) =>
...
}
Похоже, что это должно быть возможно, но я не могу понять, как!
Я попытался следующие два упрощений:
object TestingUnapply {
sealed trait Thing
case class ThingA(a: String) extends Thing
case class ThingB(b: String, thingA: ThingA) extends Thing
val x = ThingA("hello")
val y = ThingB("goodbye", ThingA("maybe"))
process(x, new { def unapply(thing: ThingA) = ThingA.unapply(thing)})
process(y, new { def unapply(thing: ThingB) = ThingB.unapply(thing).map(_._2.a)})
def process(thing: Thing, extract: { def unapply[T <: Thing](thing: T): Option[String]}) = thing match {
case extract(a) => s"The value of a is: $a"
}
}
Идея заключается в том, что я должен быть в состоянии передать любой подтип Thing и подходящий экстрактор для process
. Тем не менее, он не компилируется из-за:
[error] /tmp/proj1/TestUnapply.scala:10: type mismatch;
[error] found : AnyRef{def unapply(thing: TestingUnapply.ThingA): Option[String]}
[error] required: AnyRef{def unapply[T <: TestingUnapply.Thing](thing: T): Option[String]}
[error] process(x, new { def unapply(thing: ThingA) = ThingA.unapply(thing)})
[error] ^
[error] /tmp/proj1/TestUnapply.scala:11: type mismatch;
[error] found : AnyRef{def unapply(thing: TestingUnapply.ThingB): Option[String]}
[error] required: AnyRef{def unapply[T <: TestingUnapply.Thing](thing: T): Option[String]}
[error] process(y, new { def unapply(thing: ThingB) = ThingB.unapply(thing).map(_._2.a)})
[error] ^
Впоследствии, перемещая объявление параметра типа T
на process
, дает нам:
import scala.reflect.ClassTag
object TestingUnapply {
sealed trait Thing
case class ThingA(a: String) extends Thing
case class ThingB(b: String, thingA: ThingA) extends Thing
val x = ThingA("hello")
val y = ThingB("goodbye", ThingA("maybe"))
process(x, new { def unapply(thing: ThingA) = ThingA.unapply(thing)})
process(y, new { def unapply(thing: ThingB) = ThingB.unapply(thing).map(_._2.a)})
def process[T <: Thing: ClassTag](thing: Thing, extract: { def unapply(thing: T): Option[String]}) = thing match {
case extract(a) => s"The value of a is: $a"
}
}
Теперь дает нам другую ошибку компиляции:
[error] /tmp/TestUnapply.scala:18: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
[error] def process[T <: Thing: ClassTag](thing: Thing, extract: { def unapply(thing: T): Option[String]}) = thing match {
Я, скорее всего, делаю что-то глупое. Может кто-то мне помочь, пожалуйста?
Спасибо, да, используя абстрактный класс или черту, было о лучшем, что я мог бы придумать. Я надеялся, что есть лучший способ. Я оставлю это открытым еще пару дней, и если дальнейших предложений нет, тогда я буду принимать это как ответ. – adamretter
@adamretter, эй, просто обновите свой ответ. Поверьте, вам не нужно принимать ответ. Я просто попал в ловушку от того, почему ваши два упрощения не могут работать. После некоторого продуктивного исследования, я получил его и , тогда казалось бы, неприятное решение просто появилось без предупреждения. В любом случае, надеюсь, что это поможет. –
Спасибо @ allen-chou Мне очень нравится ваше объяснение, и, прочитав связанные статьи, яснее. Хорошая вещь :-) – adamretter