获取部分函数的已定义参数

时间:2013-05-14 13:10:40

标签: scala reflection

假设我有部分功能(类似于Akka的演员接收方法)

def receive: PartialFunction[Any, Unit] = {
    case SomeCaseClass(params) => println("whatever")
}

有没有办法获得这个函数的所有已定义参数?

我正在实现类似JSON RPC的服务结构。我基本上希望客户能够定义 通过部分功能提供服务。

def clientService = {
    case Connect(login, password) =>.....
    case SomeMessage => ...
    case SomeMethod(bla) => ..
}

e.g。第一种方法将从

翻译而来
{method: "connect", params:{login: "asdsad", password: "adsada"}}

(这部分已经有效)

现在,如果客户端已经定义了服务而另一个客户端想知道服务的可用方法,我现在需要知道服务接受哪种类型的案例,这样我就能告诉请求的客户端。我知道我可以使用对象中的常规方法轻松完成此操作,但由于我解析JSON并将其转换为case类,部分函数将简化我的API并且我喜欢漂亮的代码;)

另外我很确定必须通过反射方法,虽然我不知道在编译/运行后如何表示部分函数。

2 个答案:

答案 0 :(得分:3)

根据您可以或愿意对您的服务做出多少假设,这里是一个完全不复杂的方法,可能仍然是一个选项。它基本上依赖于1)所有可能的消息类型是已知的,b)部分函数仅在一个维度中是部分的(稍后会更多)。

我们需要一组有限的可能消息类型:

sealed trait Message

case class Hello(who: String) extends Message
case class Lunch(withWhom: String) extends Message
case class Dinner(withWhom: String) extends Message
case class Goodbye(who: String) extends Message

以及一些示例服务:

val service0: PartialFunction[Any, Unit] = {
  case Hello(who) => ()
  case Goodbye(who) => ()
}

val service1: PartialFunction[Any, Unit] = {
  case Hello(who) => ()
  case Lunch(withWhom) => ()
  case Goodbye(who) => ()
}

var services = List(service0, service1)

接下来,我们还定义了一个消息实例列表,用作接收消息的蓝图:

val simpleInstances = List(Hello("*"), Lunch("*"), Dinner("*"), Goodbye("*"))

最后,我们定义一个方法,该方法返回部分函数和可能参数列表中的接受参数:

def supportedArguments[F, T, A <: F]
                      (pf: PartialFunction[F, T], args: Iterable[A]) =

  args filter pf.isDefinedAt

漂亮的打印机:

def printSupportedArguments(services: Iterable[PartialFunction[Any, Unit]],
                            messages: Iterable[Message]) {

  services.zipWithIndex.foreach {case (s, i) =>
    val supported = supportedArguments(s, messages)
    println(s"Service $i supports $supported")
  }
}

我们走吧:

printSupportedArguments(services, simpleInstances)
  // Service 0 supports List(Hello(*), Goodbye(*))
  // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*))
  // Service 2 supports List(Goodbye(*))

如果服务不仅部分地与他们接受的消息类型相关,而且对于他们接受的消息内容也是部分的,即,如果它们在多个方向上是部分的,那么事情会变得更复杂:

val service2: PartialFunction[Any, Unit] = {
  case Hello("Thomas") => ()
  case Hello("Laura") => ()
  case Goodbye(who) => ()
}

此类服务还需要修改蓝图实例列表:

val moreInstances = simpleInstances ++ List(Hello("Thomas"), Hello("Laura"))

导致:

printSupportedArguments(services :+ service2, moreInstances)
  // Service 0 supports List(Hello(*), Goodbye(*), Hello(Thomas), Hello(Laura))
  // Service 1 supports List(Hello(*), Lunch(*), Goodbye(*), Hello(Thomas), 
  //                         Hello(Laura))
  // Service 2 supports List(Goodbye(*), Hello(Thomas), Hello(Laura))

这种方法的一系列缺点显然包括以下内容:

  • 必须知道消息类型

  • 如果服务在多个维度中是部分的,则必须也知道所有可能的消息内容

  • 使用实例Hello("*")表示Hello的任意实例,无法区分接受Hello(_)的服务和实际上只接受Hello("*") <的服务/ p>

如果您使用宏或反射(或魔术)找到真正的解决方案,请在此处发布!

答案 1 :(得分:1)

您是否询问是否可以获得导致匹配的Any arg的所有输入的列表?如果这是你的问题,那么我相信答案是否定的。你所拥有的只是isDefinedAt告诉你一个arg是否会导致匹配,如果提供给这个部分功能,但这可能不是你想要的。< / p>