我在Scala中遇到了一个匹配Case类的有趣问题......
我正在使用Akka,我的系统中的每个Actor都将使用我的功能,因此我为Actor创建了一个基类,并尝试匹配该命令......
我的命令如下所示...
sealed trait ReportCommand extends ProcessCommand
final case class onReport(key: Key, replyTo: ActorRef[ResponseBase[State]]) extend ReportCommand
虽然我构造了基类,以便可以从不同的参与者使用它,但是onReport
作为泛型参数传递给了Base Actor,以便在与case类进行模式匹配时使用...
abstract class BaseActor[E: ClassTag, R <: ReportBase[STATE], COMMAND](signal: TypeCase[R]) {
private val report = signal
def base[B <: E: ClassTag](cmd: E, state: STATE)(f: B => ReplyEffect[COMMAND, STATE]): ReplyEffect[COMMAND, STATE] =
cmd match {
case report(report) =>
Effect.reply(report.replytTo)(new ResponseBase[STATE]{
override def state: STATE = state
})
}
}
首先,如果你认为这个构造不起作用,它起作用了,我有另一个命令(我没有放在这里),它在命令类中没有泛型参数,上面的代码片段能够匹配该代码片段。
现在,当我第一次尝试这段代码时,Shapeless抱怨TypeCase的Typeable没有Map到ActorRef,所以在研究了互联网后,我发现我必须执行以下操作....
implicit def mapActorRef[T: ClassTag]: Typeable[ActorRef[T]] =
new Typeable[ActorRef[T]] {
private val typT = Typeable[T]
override def cast(t: Any) : Option[ActorRef[T]] = {
if(t==null) None
else if(t.isInstanceOf[ActorRef[_]]) {
val o= t.asInstanceOf[ActorRef[_]]
for {
_ <- typT.cast(myClassOf)
} yield o.asInstanceOf[ActorRef[T]]
} else None
}
}
def myClassOf[T: ClassTag] = implicitly[ClassTag[T]].runtimeClass
implicit def responseBaseIsTypeable[S: Typeable] : Typeable[ResponseBase[S]] =
new Typeable[ResponseBase[S]] {
private val typS = Typeable[S]
override def cast(t: Any) : Option[ResponseState[S]] = {
if(t==null) None
else if(t.isIntanceOf[ResponseBase[_]]) {
val o = t.asInstanceOf[ResponseBase[_]]
for {
_ <- typS.cast(o.state)
} yield o.asInstanceOf[ResponseBase[S]]
} else None
}
}
在这个修改之后,我没有收到来自Shapeless的任何异常,但是case report(report)
不匹配,我不知道我们如何从Scala中得到为什么它决定它不匹配的原因。在我的调试会话中,我观察到了以下情况。
我正在使用 akka 的询问模式与此演员进行交流...
val future : Future[BaseActor.ResponseBase[Actor.State]] = actorRef.ask[BaseActor.ResponseBase[Actor.State]](ref =>
Actor.onReport(key, ref)
)
现在,如果我观察BaseActor接收的cmd对象,我会看到Akka的“ask”模式将onReport
Command类中的ActorRef更改为ActorRefAdapter,当然,ActorRefAdapter是ActorRef的子类,但我不确定我在隐式中定义的将ActorRefMap到TypeCase的内容是否可以处理这些内容,但我无法找到一种方法来更改隐式以了解子类型......
不幸的是,ActorRefAdapter对于包package akka.actor.typed.internal.adapter
是私有的,所以我不能为ActorRefAdapter定义额外的Map。
所以,有人能理解为什么Scala不能匹配我的Shapeless <->TypeCase配置,并给予我一些提示吗?
谢谢你的回答。
1条答案
按热度按时间xxe27gdn1#
示例
Typeable[ActorRef[T]]
不正确。为什么你决定用
ClassTag
代替typT.cast(myClassOf)
?这不可能有意义。我猜你用了"No default Typeable for parametrized type" using Shapeless 2.1.0-RC2之类的词
如果您的目标是进行
case report(replyTo)
匹配,则可以定义问题是这个示例也不好,现在
case report(replyTo)
匹配太多了。不能为每个类型定义类型类
Typeable
的法律的示例。为多态类型(在定义良好的地方)提供示例(具体示例化)几乎是
Typeable
的全部内容,在这里和Haskell中都是如此。上面的关键短语是“定义好的地方”。它在非空容器类的情况下定义好了。显然它在函数值的情况下没有定义好。
https://github.com/milessabin/shapeless/issues/69
ResponseBase
是一个 * 非空的类似容器的东西 *,但是ActorRef
就像一个函数T => Unit
,所以不应该有一个Typeable
你应该重新考虑你的方法。